diff --git a/.gitignore b/.gitignore index 598439978..25c90c1d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,71 +1,71 @@ -*.orig -*.dcu -*.ddp -*.orig.* -*.chg.* -*.rej -*.conflict~ -*.identcache -*.recompiled.swf -run_test_*.swf -Thumbs.db -/build/ -/reports/ -/installer.cfg -/releases/ -/locales/ -/javadoc/ -/coverage/ -/dist/ -/mac/ -/testdata/decompile/ -/testdata/recompile/ -/build_exe.xml -/build_exe64.xml -/coverage.ec -/libsrc/jsyntaxpane/jsyntaxpane/src/target/ -hs_err_pid*.log -*.~* -/revision.txt -/lib/ffdec_lib.jar -/lib/README.TXT -/libsrc/avi/nbproject/private/ -/libsrc/gnujpdf/dist/ -/libsrc/jsyntaxpane/jsyntaxpane/target/ -/libsrc/ffdec_lib/build/ -/libsrc/ffdec_lib/nbproject/private/ -/libsrc/ffdec_lib/javadoc/ -/libsrc/ffdec_lib/coverage/ -/libsrc/ffdec_lib/reports/ -/libsrc/ffdec_lib/dist/ -/libsrc/ffdec_lib/testdata/decompile/ -/libsrc/ffdec_lib/testdata/recompile/ -/libsrc/ffdec_lib/testdata/directediting/ -/libsrc/ffdec_lib/coverage.ec -/libsrc/ffdec_lib/revision.txt -/libsrc/gif/nbproject/private/ -/libsrc/gif/build/ -/libsrc/jpproxy/nbproject/private/ -/libsrc/jpproxy/dist/ -/libsrc/jpproxy/build/ -/libsrc/LZMA/nbproject/private/ -/libsrc/ttf/nbproject/private/ -/libsrc/ttf/build/ -/libsrc/tablelayout/nbproject/private/ -/libsrc/tablelayout/build/ -/libsrc/tablelayout/dist/ -/libsrc/uploader/nbproject/private/ -/libsrc/uploader/build/ -/libsrc/uploader/dist/ -/jpexs_website.properties -/version.properties -/tools.properties -/nbproject/private/ -/libsrc/cmykjpeg/build/ -/libsrc/cmykjpeg/nbproject/private/ -/libsrc/Plugins/nbproject/private/ -/libsrc/Plugins/build/ -/libsrc/Plugins/dist/ -/libsrc/treetable/nbproject/private/ -/libsrc/treetable/build/ +*.orig +*.dcu +*.ddp +*.orig.* +*.chg.* +*.rej +*.conflict~ +*.identcache +*.recompiled.swf +run_test_*.swf +Thumbs.db +/build/ +/reports/ +/installer.cfg +/releases/ +/locales/ +/javadoc/ +/coverage/ +/dist/ +/mac/ +/testdata/decompile/ +/testdata/recompile/ +/build_exe.xml +/build_exe64.xml +/coverage.ec +/libsrc/jsyntaxpane/jsyntaxpane/src/target/ +hs_err_pid*.log +*.~* +/revision.txt +/lib/ffdec_lib.jar +/lib/README.TXT +/libsrc/avi/nbproject/private/ +/libsrc/gnujpdf/dist/ +/libsrc/jsyntaxpane/jsyntaxpane/target/ +/libsrc/ffdec_lib/build/ +/libsrc/ffdec_lib/nbproject/private/ +/libsrc/ffdec_lib/javadoc/ +/libsrc/ffdec_lib/coverage/ +/libsrc/ffdec_lib/reports/ +/libsrc/ffdec_lib/dist/ +/libsrc/ffdec_lib/testdata/decompile/ +/libsrc/ffdec_lib/testdata/recompile/ +/libsrc/ffdec_lib/testdata/directediting/ +/libsrc/ffdec_lib/coverage.ec +/libsrc/ffdec_lib/revision.txt +/libsrc/gif/nbproject/private/ +/libsrc/gif/build/ +/libsrc/jpproxy/nbproject/private/ +/libsrc/jpproxy/dist/ +/libsrc/jpproxy/build/ +/libsrc/LZMA/nbproject/private/ +/libsrc/ttf/nbproject/private/ +/libsrc/ttf/build/ +/libsrc/tablelayout/nbproject/private/ +/libsrc/tablelayout/build/ +/libsrc/tablelayout/dist/ +/libsrc/uploader/nbproject/private/ +/libsrc/uploader/build/ +/libsrc/uploader/dist/ +/jpexs_website.properties +/version.properties +/tools.properties +/nbproject/private/ +/libsrc/cmykjpeg/build/ +/libsrc/cmykjpeg/nbproject/private/ +/libsrc/Plugins/nbproject/private/ +/libsrc/Plugins/build/ +/libsrc/Plugins/dist/ +/libsrc/treetable/nbproject/private/ +/libsrc/treetable/build/ /libsrc/treetable/dist/ \ No newline at end of file diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ApplicationInfo.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ApplicationInfo.java index 37d49f865..14282fe9a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ApplicationInfo.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ApplicationInfo.java @@ -1,111 +1,111 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.Properties; - -/** - * - * @author JPEXS - */ -public class ApplicationInfo { - - public static final String APPLICATION_NAME = "JPEXS Free Flash Decompiler"; - - public static final String SHORT_APPLICATION_NAME = "FFDec"; - - public static final String VENDOR = "JPEXS"; - - public static String version = ""; - - public static String revision = ""; - - public static int version_major = 4; - - public static int version_minor = 0; - - public static int version_release = 0; - - public static int version_build = 0; - - public static boolean nightly = false; - - public static String applicationVerName; - - public static String shortApplicationVerName; - - public static final String PROJECT_PAGE = "https://www.free-decompiler.com/flash"; - - /** - * URL for checking new updates - */ - public static String updateCheckUrl = "https://www.free-decompiler.com/flash/update/check/?currentVersion=¤tRevision=¤tVersionMajor=¤tVersionMinor=¤tVersionRelease=¤tVersionBuild=¤tNightly="; - - /** - * URL for doing update - */ - public static String updateUrl = "https://www.free-decompiler.com/flash/update/update/?currentVersion=¤tRevision=¤tVersionMajor=¤tVersionMinor=¤tVersionRelease=¤tVersionBuild=¤tNightly="; - - static { - loadProperties(); - } - - private static void loadProperties() { - Properties prop = new Properties(); - try { - prop.load(ApplicationInfo.class.getResourceAsStream("/project.properties")); - version = prop.getProperty("version"); - revision = prop.getProperty("build"); - version_major = Integer.parseInt(prop.getProperty("version.major")); - version_minor = Integer.parseInt(prop.getProperty("version.minor")); - version_release = Integer.parseInt(prop.getProperty("version.release")); - version_build = Integer.parseInt(prop.getProperty("version.build")); - nightly = prop.getProperty("nightly").equals("true"); - if (nightly) { - version = version + " nightly build " + version_build; - } - } catch (IOException | NullPointerException | NumberFormatException ex) { - // ignore - version = "unknown"; - } - try { - updateCheckUrl = updateCheckUrl - .replace("", URLEncoder.encode(revision, "UTF-8")) - .replace("", URLEncoder.encode(version, "UTF-8")) - .replace("", "" + version_major) - .replace("", "" + version_minor) - .replace("", "" + version_release) - .replace("", "" + version_build) - .replace("", nightly ? "1" : "0"); - updateUrl = updateUrl - .replace("", URLEncoder.encode(revision, "UTF-8")) - .replace("", URLEncoder.encode(version, "UTF-8")) - .replace("", "" + version_major) - .replace("", "" + version_minor) - .replace("", "" + version_release) - .replace("", "" + version_build) - .replace("", nightly ? "1" : "0"); - } catch (UnsupportedEncodingException e) { - - } - applicationVerName = APPLICATION_NAME + " v." + version; - shortApplicationVerName = SHORT_APPLICATION_NAME + " v." + version; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Properties; + +/** + * + * @author JPEXS + */ +public class ApplicationInfo { + + public static final String APPLICATION_NAME = "JPEXS Free Flash Decompiler"; + + public static final String SHORT_APPLICATION_NAME = "FFDec"; + + public static final String VENDOR = "JPEXS"; + + public static String version = ""; + + public static String revision = ""; + + public static int version_major = 4; + + public static int version_minor = 0; + + public static int version_release = 0; + + public static int version_build = 0; + + public static boolean nightly = false; + + public static String applicationVerName; + + public static String shortApplicationVerName; + + public static final String PROJECT_PAGE = "https://www.free-decompiler.com/flash"; + + /** + * URL for checking new updates + */ + public static String updateCheckUrl = "https://www.free-decompiler.com/flash/update/check/?currentVersion=¤tRevision=¤tVersionMajor=¤tVersionMinor=¤tVersionRelease=¤tVersionBuild=¤tNightly="; + + /** + * URL for doing update + */ + public static String updateUrl = "https://www.free-decompiler.com/flash/update/update/?currentVersion=¤tRevision=¤tVersionMajor=¤tVersionMinor=¤tVersionRelease=¤tVersionBuild=¤tNightly="; + + static { + loadProperties(); + } + + private static void loadProperties() { + Properties prop = new Properties(); + try { + prop.load(ApplicationInfo.class.getResourceAsStream("/project.properties")); + version = prop.getProperty("version"); + revision = prop.getProperty("build"); + version_major = Integer.parseInt(prop.getProperty("version.major")); + version_minor = Integer.parseInt(prop.getProperty("version.minor")); + version_release = Integer.parseInt(prop.getProperty("version.release")); + version_build = Integer.parseInt(prop.getProperty("version.build")); + nightly = prop.getProperty("nightly").equals("true"); + if (nightly) { + version = version + " nightly build " + version_build; + } + } catch (IOException | NullPointerException | NumberFormatException ex) { + // ignore + version = "unknown"; + } + try { + updateCheckUrl = updateCheckUrl + .replace("", URLEncoder.encode(revision, "UTF-8")) + .replace("", URLEncoder.encode(version, "UTF-8")) + .replace("", "" + version_major) + .replace("", "" + version_minor) + .replace("", "" + version_release) + .replace("", "" + version_build) + .replace("", nightly ? "1" : "0"); + updateUrl = updateUrl + .replace("", URLEncoder.encode(revision, "UTF-8")) + .replace("", URLEncoder.encode(version, "UTF-8")) + .replace("", "" + version_major) + .replace("", "" + version_minor) + .replace("", "" + version_release) + .replace("", "" + version_build) + .replace("", nightly ? "1" : "0"); + } catch (UnsupportedEncodingException e) { + + } + applicationVerName = APPLICATION_NAME + " v." + version; + shortApplicationVerName = SHORT_APPLICATION_NAME + " v." + version; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ReadOnlyTagList.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ReadOnlyTagList.java index faf327b5c..7edda7b65 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ReadOnlyTagList.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ReadOnlyTagList.java @@ -1,62 +1,62 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash; - -import com.jpexs.decompiler.flash.tags.Tag; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class ReadOnlyTagList implements Iterable { - - public static final ReadOnlyTagList EMPTY = new ReadOnlyTagList(new ArrayList<>()); - - private final List list; - - public ReadOnlyTagList(List list) { - this.list = list; - } - - @Override - public Iterator iterator() { - return list.iterator(); - } - - public int size() { - return list.size(); - } - - public boolean isEmpty() { - return list.isEmpty(); - } - - public Tag get(int index) { - return list.get(index); - } - - public int indexOf(Tag tag) { - return list.indexOf(tag); - } - - public ArrayList toArrayList() { - return new ArrayList<>(list); - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash; + +import com.jpexs.decompiler.flash.tags.Tag; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class ReadOnlyTagList implements Iterable { + + public static final ReadOnlyTagList EMPTY = new ReadOnlyTagList(new ArrayList<>()); + + private final List list; + + public ReadOnlyTagList(List list) { + this.list = list; + } + + @Override + public Iterator iterator() { + return list.iterator(); + } + + public int size() { + return list.size(); + } + + public boolean isEmpty() { + return list.isEmpty(); + } + + public Tag get(int index) { + return list.get(index); + } + + public int indexOf(Tag tag) { + return list.indexOf(tag); + } + + public ArrayList toArrayList() { + return new ArrayList<>(list); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFSearch.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFSearch.java index 67584ea52..f2baed8e0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFSearch.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFSearch.java @@ -1,157 +1,157 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -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; - 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, null, null, false, true, true); - boolean valid = swf.fileSize > 0 - && swf.version > 0 - && (!swf.getTags().isEmpty() || noCheck) - && swf.version <= SWF.MAX_VERSION; - 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(); - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +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; + 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, null, null, false, true, true); + boolean valid = swf.fileSize > 0 + && swf.version > 0 + && (!swf.getTags().isEmpty() || noCheck) + && swf.version <= SWF.MAX_VERSION; + 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/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index e4189d543..3dca8d4e0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -1,2911 +1,2911 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.abc.avm2; - -import com.jpexs.decompiler.flash.EndOfStreamException; -import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.ABCInputStream; -import com.jpexs.decompiler.flash.abc.CopyOutputStream; -import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorGetSet; -import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorJumps; -import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorRegistersOld; -import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorSimpleOld; -import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2ExecutionException; -import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2VerifyErrorException; -import com.jpexs.decompiler.flash.abc.avm2.graph.AVM2Graph; -import com.jpexs.decompiler.flash.abc.avm2.graph.AVM2GraphSource; -import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; -import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2InstructionFlag; -import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; -import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; -import com.jpexs.decompiler.flash.abc.avm2.instructions.UnknownInstruction; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Lf32Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Lf64Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Li16Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Li32Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Li8Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Sf32Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Sf64Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Si16Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Si32Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Si8Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Sxi16Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Sxi1Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Sxi8Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DivideIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.ModuloIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NegateIIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NegateIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NotIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitAndIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitNotIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitOrIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitXorIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.LShiftIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.RShiftIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.URShiftIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.EqualsIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterEqualsIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterThanIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessEqualsIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessThanIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.StrictEqualsIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructPropIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructSuperIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewActivationIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewArrayIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewCatchIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewClassIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewObjectIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugFileIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugLineIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallMethodIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallPropLexIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallPropVoidIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallPropertyIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallStaticIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallSuperIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallSuperVoidIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfEqIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfFalseIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfGeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfGtIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfLeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfLtIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfNGeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfNGtIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfNLeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfNLtIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfNeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfStrictEqIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfStrictNeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfTrueIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.LookupSwitchIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.DecLocalIIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.DecLocalIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocal0Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocal1Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocal2Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocal3Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalTypeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.KillIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocal0Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocal1Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocal2Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocal3Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.DeletePropertyIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.FindDefIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.FindPropertyIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.FindPropertyStrictIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetDescendantsIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetGlobalScopeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetGlobalSlotIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetLexIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetPropertyIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetScopeObjectIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetSlotIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetSuperIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.HasNext2Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.HasNextIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.InIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.InitPropertyIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.LabelIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NextNameIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NextValueIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NopIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetGlobalSlotIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetPropertyIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetSlotIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetSuperIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.AbsJumpIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.AddDIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.AddPIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.AllocIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.BkptIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.BkptLineIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CallInterfaceIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CallSuperIdIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CodeGenOpIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CoerceBIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CoerceDIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CoerceIIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CoerceOIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CoerceUIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.ConcatIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.ConvertF4Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.ConvertFIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.ConvertMIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.ConvertMPIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DecLocalPIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DecodeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DecrementPIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DelDescendantsIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DeletePropertyLateIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DividePIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DoubleToAtomIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.FindPropGlobalIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.GetOuterScopeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.IncLocalPIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.IncrementPIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.InvalidIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.Lf32x4Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.MarkIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.ModuloPIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.MultiplyPIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.NegatePIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.PrologueIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.PushConstantIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.PushDNanIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.PushDecimalIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.PushFloat4Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.PushFloatIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.SendEnterIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.SetPropertyLateIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.Sf32x4Ins; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.SubtractPIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.SweepIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.TimestampIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.UnPlusIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.VerifyOpIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.VerifyPassIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.WbIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopScopeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushDoubleIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushFalseIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNamespaceIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNanIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNullIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushScopeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushStringIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushTrueIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUIntIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushWithIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.SwapIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ApplyTypeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.AsTypeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.AsTypeLateIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceAIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceOrConvertTypeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceSIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertBIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertDIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertIIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertOIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertSIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertUIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.InstanceOfIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.IsTypeIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.IsTypeLateIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.types.TypeOfIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.CheckFilterIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.DXNSIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.DXNSLateIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.EscXAttrIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.EscXElemIns; -import com.jpexs.decompiler.flash.abc.avm2.model.CoerceAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.ConvertAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.InitPropertyAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.NewFunctionAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.ReturnVoidAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.SetPropertyAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.SetSlotAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.SetTypeAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.WithAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.clauses.DeclarationAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForEachInAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForInAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.parser.script.PropertyAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; -import com.jpexs.decompiler.flash.abc.types.ABCException; -import com.jpexs.decompiler.flash.abc.types.AssignedValue; -import com.jpexs.decompiler.flash.abc.types.ConvertData; -import com.jpexs.decompiler.flash.abc.types.MethodBody; -import com.jpexs.decompiler.flash.abc.types.MethodInfo; -import com.jpexs.decompiler.flash.abc.types.Multiname; -import com.jpexs.decompiler.flash.abc.types.ValueKind; -import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction; -import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; -import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; -import com.jpexs.decompiler.flash.abc.types.traits.Traits; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.dumpview.DumpInfo; -import com.jpexs.decompiler.flash.ecma.Undefined; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; -import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; -import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; -import com.jpexs.decompiler.graph.Block; -import com.jpexs.decompiler.graph.DottedChain; -import com.jpexs.decompiler.graph.GraphPart; -import com.jpexs.decompiler.graph.GraphSourceItem; -import com.jpexs.decompiler.graph.GraphTargetItem; -import com.jpexs.decompiler.graph.ScopeStack; -import com.jpexs.decompiler.graph.SimpleValue; -import com.jpexs.decompiler.graph.TranslateStack; -import com.jpexs.decompiler.graph.TypeItem; -import com.jpexs.decompiler.graph.model.BinaryOpItem; -import com.jpexs.decompiler.graph.model.ExitItem; -import com.jpexs.decompiler.graph.model.IfItem; -import com.jpexs.decompiler.graph.model.ScriptEndItem; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.ReflectionTools; -import com.jpexs.helpers.stat.Statistics; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class AVM2Code implements Cloneable { - - private static final Logger logger = Logger.getLogger(AVM2Code.class.getName()); - - private static final boolean DEBUG_MODE = false; - - public static int toSourceLimit = -1; - - public List code; - - public static boolean DEBUG_REWRITE = false; - - public static final int OPT_U30 = 0x100; - - public static final int OPT_U8 = 0x200; - - public static final int OPT_S24 = 0x300; - - public static final int OPT_CASE_OFFSETS = 0x400; - - public static final int OPT_S8 = 0x500; - - public static final int OPT_S16 = 0x600; - - public static final int DAT_MULTINAME_INDEX = OPT_U30 + 0x01; - - public static final int DAT_ARG_COUNT = OPT_U30 + 0x02; - - public static final int DAT_METHOD_INDEX = OPT_U30 + 0x03; - - public static final int DAT_STRING_INDEX = OPT_U30 + 0x04; - - public static final int DAT_DEBUG_TYPE = OPT_U8 + 0x05; - - public static final int DAT_REGISTER_INDEX = OPT_U8 + 0x06; - - public static final int DAT_LINENUM = OPT_U30 + 0x07; - - public static final int DAT_LOCAL_REG_INDEX = OPT_U30 + 0x08; - - public static final int DAT_SLOT_INDEX = OPT_U30 + 0x09; - - public static final int DAT_SCOPE_INDEX = OPT_U30 + 0x0A; - - public static final int DAT_OFFSET = OPT_S24 + 0x0B; - - public static final int DAT_EXCEPTION_INDEX = OPT_U30 + 0x0C; - - public static final int DAT_CLASS_INDEX = OPT_U30 + 0x0D; - - public static final int DAT_INT_INDEX = OPT_U30 + 0x0E; - - public static final int DAT_UINT_INDEX = OPT_U30 + 0x0F; - - public static final int DAT_DOUBLE_INDEX = OPT_U30 + 0x10; - - public static final int DAT_DECIMAL_INDEX = OPT_U30 + 0x11; - - public static final int DAT_CASE_BASEOFFSET = OPT_S24 + 0x12; - - public static final int DAT_NUMBER_CONTEXT = OPT_U30 + 0x13; - - public static final int DAT_DISPATCH_ID = OPT_U30 + 0x14; - - public static final int DAT_FLOAT_INDEX = OPT_U30 + 0x15; - - public static final int DAT_FLOAT4_INDEX = OPT_U30 + 0x16; - - public static final int DAT_NAMESPACE_INDEX = OPT_U30 + 0x17; - - public static String operandTypeSizeToString(int ot) { - int sizeType = ot & 0xff00; - switch (sizeType) { - case OPT_U30: - return "U30"; - case OPT_S16: - return "S16"; - case OPT_U8: - return "U8"; - case OPT_S8: - return "S8"; - case OPT_S24: - return "S24"; - case OPT_CASE_OFFSETS: - return "S24(=n), S24[n]"; - } - return ""; - } - - private static Map operandDataTypeIdentifiers = ReflectionTools.getConstNamesMap(AVM2Code.class, Integer.class, "^DAT_(.*)$"); - - public static String operandTypeToString(int ot, boolean withTypeSize) { - String typeSize = operandTypeSizeToString(ot); - if (ot == OPT_CASE_OFFSETS) { - return "number" + (withTypeSize ? "(U30)" : "") + ", offset" + (withTypeSize ? "(S24)" : "") + ", offset" + (withTypeSize ? "(S24)" : "") + ", ..."; - } - if (operandDataTypeIdentifiers.containsKey(ot)) { - String dataType = operandDataTypeIdentifiers.get(ot); - return dataType + (withTypeSize ? "(" + typeSize + ")" : ""); - } else { - return typeSize; - } - - } - - public static final InstructionDefinition[] instructionSet = new InstructionDefinition[256]; - - public static final InstructionDefinition[] allInstructionSet = new InstructionDefinition[]{ - /*0x00*/null, - /*0x01*/ new BkptIns(), - /*0x02*/ new NopIns(), - /*0x03*/ new ThrowIns(), - /*0x04*/ new GetSuperIns(), - /*0x05*/ new SetSuperIns(), - /*0x06*/ new DXNSIns(), - /*0x07*/ new DXNSLateIns(), - /*0x08*/ new KillIns(), - /*0x09*/ new LabelIns(), - /*0x0A*/ new Lf32x4Ins(), - /*0x0B*/ new Sf32x4Ins(), - /*0x0C*/ new IfNLtIns(), - /*0x0D*/ new IfNLeIns(), - /*0x0E*/ new IfNGtIns(), - /*0x0F*/ new IfNGeIns(), - /*0x10*/ new JumpIns(), - /*0x11*/ new IfTrueIns(), - /*0x12*/ new IfFalseIns(), - /*0x13*/ new IfEqIns(), - /*0x14*/ new IfNeIns(), - /*0x15*/ new IfLtIns(), - /*0x16*/ new IfLeIns(), - /*0x17*/ new IfGtIns(), - /*0x18*/ new IfGeIns(), - /*0x19*/ new IfStrictEqIns(), - /*0x1A*/ new IfStrictNeIns(), - /*0x1B*/ new LookupSwitchIns(), - /*0x1C*/ new PushWithIns(), - /*0x1D*/ new PopScopeIns(), - /*0x1E*/ new NextNameIns(), - /*0x1F*/ new HasNextIns(), - /*0x20*/ new PushNullIns(), - /*0x21*/ new PushUndefinedIns(), - /*0x22*/ new PushFloatIns(), //major 47+ - /*0x22*/ new PushConstantIns(), //before major 47 - /*0x23*/ new NextValueIns(), - /*0x24*/ new PushByteIns(), - /*0x25*/ new PushShortIns(), - /*0x26*/ new PushTrueIns(), - /*0x27*/ new PushFalseIns(), - /*0x28*/ new PushNanIns(), - /*0x29*/ new PopIns(), - /*0x2A*/ new DupIns(), - /*0x2B*/ new SwapIns(), - /*0x2C*/ new PushStringIns(), - /*0x2D*/ new PushIntIns(), - /*0x2E*/ new PushUIntIns(), - /*0x2F*/ new PushDoubleIns(), - /*0x30*/ new PushScopeIns(), - /*0x31*/ new PushNamespaceIns(), - /*0x32*/ new HasNext2Ins(), - /*0x33*/ new PushDecimalIns(), //pushdecimal(minor 17), lix8 (internal-only) according to Tamarin - /*0x34*/ new PushDNanIns(), //pushdnan according to Flex SDK, lix16 (internal-only) according to Tamarin - /*0x35*/ new Li8Ins(), - /*0x36*/ new Li16Ins(), - /*0x37*/ new Li32Ins(), - /*0x38*/ new Lf32Ins(), - /*0x39*/ new Lf64Ins(), - /*0x3A*/ new Si8Ins(), - /*0x3B*/ new Si16Ins(), - /*0x3C*/ new Si32Ins(), - /*0x3D*/ new Sf32Ins(), - /*0x3E*/ new Sf64Ins(), - /*0x3F*/ null, - /*0x40*/ new NewFunctionIns(), - /*0x41*/ new CallIns(), - /*0x42*/ new ConstructIns(), - /*0x43*/ new CallMethodIns(), - /*0x44*/ new CallStaticIns(), - /*0x45*/ new CallSuperIns(), - /*0x46*/ new CallPropertyIns(), - /*0x47*/ new ReturnVoidIns(), - /*0x48*/ new ReturnValueIns(), - /*0x49*/ new ConstructSuperIns(), - /*0x4A*/ new ConstructPropIns(), - /*0x4B*/ new CallSuperIdIns(), - /*0x4C*/ new CallPropLexIns(), - /*0x4D*/ new CallInterfaceIns(), - /*0x4E*/ new CallSuperVoidIns(), - /*0x4F*/ new CallPropVoidIns(), - /*0x50*/ new Sxi1Ins(), - /*0x51*/ new Sxi8Ins(), - /*0x52*/ new Sxi16Ins(), - /*0x53*/ new ApplyTypeIns(), - /*0x54*/ new PushFloat4Ins(), //major 47+ - /*0x55*/ new NewObjectIns(), - /*0x56*/ new NewArrayIns(), - /*0x57*/ new NewActivationIns(), - /*0x58*/ new NewClassIns(), - /*0x59*/ new GetDescendantsIns(), - /*0x5A*/ new NewCatchIns(), - /*0x5B*/ new DelDescendantsIns(), //deldescendants according to Flex, findpropglobalstrict(internal-only) according to Tamarin - /*0x5C*/ new FindPropGlobalIns(), //Tamarin (internal-only) - /*0x5D*/ new FindPropertyStrictIns(), - /*0x5E*/ new FindPropertyIns(), - /*0x5F*/ new FindDefIns(), - /*0x60*/ new GetLexIns(), - /*0x61*/ new SetPropertyIns(), - /*0x62*/ new GetLocalIns(), - /*0x63*/ new SetLocalIns(), - /*0x64*/ new GetGlobalScopeIns(), - /*0x65*/ new GetScopeObjectIns(), - /*0x66*/ new GetPropertyIns(), - /*0x67*/ new GetOuterScopeIns(), // new GetPropertyLateIns() - /*0x68*/ new InitPropertyIns(), - /*0x69*/ new SetPropertyLateIns(), - /*0x6A*/ new DeletePropertyIns(), - /*0x6B*/ new DeletePropertyLateIns(), - /*0x6C*/ new GetSlotIns(), - /*0x6D*/ new SetSlotIns(), - /*0x6E*/ new GetGlobalSlotIns(), - /*0x6F*/ new SetGlobalSlotIns(), - /*0x70*/ new ConvertSIns(), - /*0x71*/ new EscXElemIns(), - /*0x72*/ new EscXAttrIns(), - /*0x73*/ new ConvertIIns(), - /*0x74*/ new ConvertUIns(), - /*0x75*/ new ConvertDIns(), - /*0x76*/ new ConvertBIns(), - /*0x77*/ new ConvertOIns(), - /*0x78*/ new CheckFilterIns(), - /*0x79*/ new ConvertMIns(), //minor 17 (Flex) - /*0x79*/ new ConvertFIns(), //major 47+, SWF 15+ - /*0x7A*/ new ConvertMPIns(), //minor 17 (Flex) - /*0x7A*/ new UnPlusIns(), //major 47+, SWF 15+ - /*0x7B*/ new ConvertF4Ins(), //major 47+, SWF 15+ - /*0x7C*/ null, - /*0x7D*/ null, - /*0x7E*/ null, - /*0x7F*/ null, - /*0x80*/ new CoerceIns(), - /*0x81*/ new CoerceBIns(), - /*0x82*/ new CoerceAIns(), - /*0x83*/ new CoerceIIns(), - /*0x84*/ new CoerceDIns(), - /*0x85*/ new CoerceSIns(), - /*0x86*/ new AsTypeIns(), - /*0x87*/ new AsTypeLateIns(), - /*0x88*/ new CoerceUIns(), - /*0x89*/ new CoerceOIns(), - /*0x8A*/ null, - /*0x8B*/ null, - /*0x8C*/ null, - /*0x8D*/ null, - /*0x8E*/ null, - /*0x8F*/ new NegatePIns(), - /*0x90*/ new NegateIns(), - /*0x91*/ new IncrementIns(), - /*0x92*/ new IncLocalIns(), - /*0x93*/ new DecrementIns(), - /*0x94*/ new DecLocalIns(), - /*0x95*/ new TypeOfIns(), - /*0x96*/ new NotIns(), - /*0x97*/ new BitNotIns(), - /*0x98*/ null, - /*0x99*/ null, - /*0x9A*/ new ConcatIns(), - /*0x9B*/ new AddDIns(), - /*0x9C*/ new IncrementPIns(), - /*0x9D*/ new IncLocalPIns(), - /*0x9E*/ new DecrementPIns(), - /*0x9F*/ new DecLocalPIns(), - /*0xA0*/ new AddIns(), - /*0xA1*/ new SubtractIns(), - /*0xA2*/ new MultiplyIns(), - /*0xA3*/ new DivideIns(), - /*0xA4*/ new ModuloIns(), - /*0xA5*/ new LShiftIns(), - /*0xA6*/ new RShiftIns(), - /*0xA7*/ new URShiftIns(), - /*0xA8*/ new BitAndIns(), - /*0xA9*/ new BitOrIns(), - /*0xAA*/ new BitXorIns(), - /*0xAB*/ new EqualsIns(), - /*0xAC*/ new StrictEqualsIns(), - /*0xAD*/ new LessThanIns(), - /*0xAE*/ new LessEqualsIns(), - /*0xAF*/ new GreaterThanIns(), - /*0xB0*/ new GreaterEqualsIns(), - /*0xB1*/ new InstanceOfIns(), - /*0xB2*/ new IsTypeIns(), - /*0xB3*/ new IsTypeLateIns(), - /*0xB4*/ new InIns(), - /*0xB5*/ new AddPIns(), - /*0xB6*/ new SubtractPIns(), - /*0xB7*/ new MultiplyPIns(), - /*0xB8*/ new DividePIns(), - /*0xB9*/ new ModuloPIns(), - /*0xBA*/ null, - /*0xBB*/ null, - /*0xBC*/ null, - /*0xBD*/ null, - /*0xBE*/ null, - /*0xBF*/ null, - /*0xC0*/ new IncrementIIns(), - /*0xC1*/ new DecrementIIns(), - /*0xC2*/ new IncLocalIIns(), - /*0xC3*/ new DecLocalIIns(), - /*0xC4*/ new NegateIIns(), - /*0xC5*/ new AddIIns(), - /*0xC6*/ new SubtractIIns(), - /*0xC7*/ new MultiplyIIns(), - /*0xC8*/ null, - /*0xC9*/ null, - /*0xCA*/ null, - /*0xCB*/ null, - /*0xCC*/ null, - /*0xCD*/ null, - /*0xCE*/ null, - /*0xCF*/ null, - /*0xD0*/ new GetLocal0Ins(), - /*0xD1*/ new GetLocal1Ins(), - /*0xD2*/ new GetLocal2Ins(), - /*0xD3*/ new GetLocal3Ins(), - /*0xD4*/ new SetLocal0Ins(), - /*0xD5*/ new SetLocal1Ins(), - /*0xD6*/ new SetLocal2Ins(), - /*0xD7*/ new SetLocal3Ins(), - /*0xD8*/ null, - /*0xD9*/ null, - /*0xDA*/ null, - /*0xDB*/ null, - /*0xDC*/ null, - /*0xDD*/ null, - /*0xDE*/ null, - /*0xDF*/ null, - /*0xE0*/ null, - /*0xE1*/ null, - /*0xE2*/ null, - /*0xE3*/ null, - /*0xE4*/ null, - /*0xE5*/ null, - /*0xE6*/ null, - /*0xE7*/ null, - /*0xE8*/ null, - /*0xE9*/ null, - /*0xEA*/ null, - /*0xEB*/ null, - /*0xEC*/ null, - /*0xED*/ new InvalidIns(), - /*0xEE*/ new AbsJumpIns(), - /*0xEF*/ new DebugIns(), - /*0xF0*/ new DebugLineIns(), - /*0xF1*/ new DebugFileIns(), - /*0xF2*/ new BkptLineIns(), - /*0xF3*/ new TimestampIns(), - /*0xF4*/ null, - /*0xF5*/ new VerifyPassIns(), - /*0xF6*/ new AllocIns(), - /*0xF7*/ new MarkIns(), - /*0xF8*/ new WbIns(), - /*0xF9*/ new PrologueIns(), - /*0xFA*/ new SendEnterIns(), - /*0xFB*/ new DoubleToAtomIns(), - /*0xFC*/ new SweepIns(), - /*0xFD*/ new CodeGenOpIns(), - /*0xFE*/ new VerifyOpIns(), - /*0xFF*/ new DecodeIns(),}; - // endoflist - - static { - - for (int i = 0; i < allInstructionSet.length; i++) { - if (allInstructionSet[i] != null) { - int opCode = allInstructionSet[i].instructionCode; - if (instructionSet[opCode] == null) { - instructionSet[opCode] = allInstructionSet[i]; - } else if (instructionSet[opCode].hasFlag(AVM2InstructionFlag.NO_FLASH_PLAYER) && !allInstructionSet[i].hasFlag(AVM2InstructionFlag.NO_FLASH_PLAYER)) { - instructionSet[opCode] = allInstructionSet[i]; - } //Prefer without decimal: - else if (instructionSet[opCode].hasFlag(AVM2InstructionFlag.ES4_NUMERICS_MINOR) && !allInstructionSet[i].hasFlag(AVM2InstructionFlag.ES4_NUMERICS_MINOR)) { - instructionSet[opCode] = allInstructionSet[i]; - } //Prefer without float: - else if (instructionSet[opCode].hasFlag(AVM2InstructionFlag.FLOAT_MAJOR) && !allInstructionSet[i].hasFlag(AVM2InstructionFlag.FLOAT_MAJOR)) { - instructionSet[opCode] = allInstructionSet[i]; - } - } - } - - for (int i = 0; - i < instructionSet.length; - i++) { - if (instructionSet[i] == null) { - instructionSet[i] = new UnknownInstruction(i); - } - } - - } - - public static final String IDENTOPEN = "/*IDENTOPEN*/"; - - public static final String IDENTCLOSE = "/*IDENTCLOSE*/"; - - public AVM2Code() { - code = new ArrayList<>(); - } - - public AVM2Code(int capacity) { - code = new ArrayList<>(capacity); - } - - public AVM2Code(ArrayList instructions) { - code = instructions; - } - - public Object execute(HashMap arguments, AVM2ConstantPool constants) throws AVM2ExecutionException { - return execute(arguments, constants, null); - } - - public Object execute(HashMap arguments, AVM2ConstantPool constants, AVM2RuntimeInfo runtimeInfo) throws AVM2ExecutionException { - int pos = 0; - LocalDataArea lda = new LocalDataArea(); - lda.methodName = "methodName"; // todo: needed for VerifyError exception message - lda.localRegisters = arguments; - lda.runtimeInfo = runtimeInfo; - - for (AVM2Instruction ins : code) { - ins.definition.verify(lda, constants, ins); - } - - while (pos < code.size()) { - AVM2Instruction ins = code.get(pos); - if (!ins.definition.execute(lda, constants, ins)) { - return null; - } - - if (lda.jump != null) { - try { - pos = adr2pos(lda.jump); - } catch (ConvertException ex) { - throw new AVM2VerifyErrorException(AVM2VerifyErrorException.BRANCH_TARGET_INVALID_INSTRUCTION, lda.isDebug()); - } - lda.jump = null; - } else { - pos++; - } - - if (lda.returnValue != null) { - return lda.returnValue; - } - } - - return Undefined.INSTANCE; - } - - public void calculateDebugFileLine(ABC abc) { - calculateDebugFileLine(null, 0, 0, abc, new HashSet<>()); - } - - private boolean calculateDebugFileLine(String debugFile, int debugLine, int pos, ABC abc, Set seen) { - while (pos < code.size()) { - AVM2Instruction ins = code.get(pos); - if (seen.contains(pos)) { - return true; - } - - seen.add(pos); - - if (ins.definition instanceof DebugFileIns) { - debugFile = abc.constants.getString(ins.operands[0]); - } - - if (ins.definition instanceof DebugLineIns) { - debugLine = ins.operands[0]; - } - - ins.setFileLine(debugFile, debugLine); - - if (ins.definition instanceof NewFunctionIns) { - //Only analyze NewFunction objects that are not immediately discarded by Pop. - //This avoids bogus functions used in obfuscation or special compilers that can lead to infinite recursion. - if ((pos + 1 < code.size()) && !(code.get(pos + 1).definition instanceof PopIns)) { - MethodBody innerBody = abc.findBody(ins.operands[0]); - if (innerBody != null) { //Ignore functions without body - innerBody.getCode().calculateDebugFileLine(debugFile, debugLine, 0, abc, new HashSet<>()); - } - } - } - - if (ins.definition instanceof ReturnValueIns) { - return true; - } - if (ins.definition instanceof ReturnVoidIns) { - return true; - } - if (ins.definition instanceof JumpIns) { - try { - pos = adr2pos(ins.getTargetAddress()); - continue; - } catch (ConvertException ex) { - return false; - } - } else if (ins.definition instanceof IfTypeIns) { - try { - int newpos = adr2pos(ins.getTargetAddress()); - calculateDebugFileLine(debugFile, debugLine, newpos, abc, seen); - } catch (ConvertException ex) { - return false; - } - } - if (ins.definition instanceof LookupSwitchIns) { - for (int i = 0; i < ins.operands.length; i++) { - if (i == 1) { - continue; - } - try { - int newpos = adr2pos(pos2adr(pos) + ins.operands[i]); - if (!calculateDebugFileLine(debugFile, debugLine, newpos, abc, seen)) { - return false; - } - } catch (ConvertException ex) { - return false; - } - } - } - pos++; - } - return true; - } - - /** - * Removes nonexistent indices to constants from instruction operands. - * - * @param constants - */ - public void removeWrongIndices(AVM2ConstantPool constants) { - for (AVM2Instruction ins : code) { - for (int i = 0; i < ins.definition.operands.length; i++) { - if (ins.definition.operands[i] == DAT_MULTINAME_INDEX && ins.operands[i] >= constants.getMultinameCount()) { - ins.operands[i] = 0; - } - if (ins.definition.operands[i] == DAT_DOUBLE_INDEX && ins.operands[i] >= constants.getDoubleCount()) { - ins.operands[i] = 0; - } - if (ins.definition.operands[i] == DAT_INT_INDEX && ins.operands[i] >= constants.getIntCount()) { - ins.operands[i] = 0; - } - if (ins.definition.operands[i] == DAT_UINT_INDEX && ins.operands[i] >= constants.getUIntCount()) { - ins.operands[i] = 0; - } - if (ins.definition.operands[i] == DAT_STRING_INDEX && ins.operands[i] >= constants.getStringCount()) { - ins.operands[i] = 0; - } - } - } - } - - public AVM2Code(ABCInputStream ais, MethodBody body) throws IOException { - Map codeMap = new HashMap<>(); - DumpInfo diParent = ais.dumpInfo; - List addresses = new ArrayList<>(); - //Do not add new jumps when processing these addresses (unreachable code,etc.) - List unAdresses = new ArrayList<>(); - //Handle lookupswitches at the end - they can be invalid. Handle other instruction first so we can decide lookupswitch to be invalid based on other instructions inside it - //Flashplayer does not check casecount in lookupswitch instruction so the instruction can "be" long and over other instructions - List switchAddresses = new ArrayList<>(); - int availableBytes = ais.available(); - for (int i = 0; i < availableBytes; i++) { - codeMap.put((long) i, new AVM2Instruction(i, AVM2Instructions.Nop, null)); - } - - long startPos = ais.getPosition(); - addresses.add(startPos); - if (body != null) { - for (ABCException e : body.exceptions) { - addresses.add((long) e.start); - addresses.add((long) e.end); - addresses.add((long) e.target); - } - } - - loopaddr: - while (!addresses.isEmpty() || !switchAddresses.isEmpty() || !unAdresses.isEmpty()) { - long address; - boolean isSwitch = false; - boolean handleJumps = true; - if (!addresses.isEmpty()) { - address = addresses.remove(0); - } else if (!switchAddresses.isEmpty()) { - address = switchAddresses.remove(0); - isSwitch = true; - } else { - address = unAdresses.remove(0); - handleJumps = false; - } - if (address < startPos) // no jump outside block - { - continue; - } - try { - ais.seek(address); - while (ais.available() > 0) { - long startOffset = ais.getPosition(); - - if (codeMap.containsKey(startOffset) && !(codeMap.get(startOffset).definition instanceof NopIns)) { - continue loopaddr; - } - - DumpInfo di = ais.newDumpLevel("instruction", "instruction"); - InstructionDefinition instr = null; - try { - int instructionCode = ais.read("instructionCode"); - instr = instructionSet[instructionCode]; - if (instructionCode == AVM2Instructions.LookupSwitch) { - if (!isSwitch) { - switchAddresses.add(startOffset); - continue loopaddr; - } else { - isSwitch = false; - } - } - if (di != null) { - di.name = instr.instructionName; - } - if (instr != null) { - int[] actualOperands = null; - - if (instructionCode == AVM2Instructions.LookupSwitch) { // switch - int firstOperand = ais.readS24("default_offset"); - int case_count = ais.readU30("case_count"); - long afterCasePos = ais.getPosition() + 3 * (case_count + 1); - - boolean invalidSwitch = false; - //If there are already some instructions in the lookupswitch bytes, the lookupswitch is invalid (obfuscation) - for (long a = startOffset; a < afterCasePos; a++) { - if (codeMap.containsKey(a) && (!(codeMap.get(a).definition instanceof NopIns))) { - invalidSwitch = true; - break; - } - } - - long totalBytes = ais.getPosition() + ais.available(); - - //If the lookupswitch case_count are larger than available bytes, the lookupswitch is invalid (obfuscation) - if (afterCasePos > totalBytes) { - invalidSwitch = true; - } - if (invalidSwitch) { - continue loopaddr; - } else { - actualOperands = new int[case_count + 3]; - actualOperands[0] = firstOperand; - actualOperands[1] = case_count; - for (int c = 0; c < case_count + 1; c++) { - actualOperands[2 + c] = ais.readS24("actualOperand"); - } - } - } else if (instr.operands.length > 0) { - actualOperands = new int[instr.operands.length]; - for (int op = 0; op < instr.operands.length; op++) { - switch (instr.operands[op] & 0xff00) { - case OPT_U30: - actualOperands[op] = ais.readU30("operand"); - break; - case OPT_S16: - actualOperands[op] = (short) ais.readU30("operand"); - break; - case OPT_U8: - actualOperands[op] = ais.read("operand"); - break; - case OPT_S8: - actualOperands[op] = (byte) ais.read("operand"); - break; - case OPT_S24: - actualOperands[op] = ais.readS24("operand"); - break; - } - } - } - - AVM2Instruction ai = new AVM2Instruction(startOffset, instr, actualOperands); - long endOffset = ais.getPosition(); - - boolean hasRoom = true; - for (long p = startOffset; p < endOffset; p++) { - if (codeMap.containsKey(p) && !(codeMap.get(p).definition instanceof NopIns)) { - hasRoom = false; - } - } - - //There is no room for this instruction (it is invalid?) - if (!hasRoom) { - continue loopaddr; - } - for (long p = startOffset; p < endOffset; p++) { - codeMap.put(p, ai); - } - - if ((instr instanceof IfTypeIns)) { - if (handleJumps) { - long target = ais.getPosition() + actualOperands[0]; - addresses.add(target); - } else { - actualOperands[0] = 0; - } - } - - if (instr instanceof JumpIns) { - if (handleJumps) { - long target = ais.getPosition() + actualOperands[0]; - addresses.add(target); - unAdresses.add(ais.getPosition()); - continue loopaddr; - } else { - actualOperands[0] = 0; - } - } - - if (instr.isExitInstruction()) { //do not process jumps if there is return/throw instruction - if (handleJumps) { - unAdresses.add(ais.getPosition()); - continue loopaddr; - } - } - if ((instr instanceof LookupSwitchIns) && actualOperands != null) { - if (handleJumps) { - addresses.add(startOffset + actualOperands[0]); - - for (int c = 2; c < actualOperands.length; c++) { - addresses.add(startOffset + actualOperands[c]); - } - unAdresses.add(ais.getPosition()); - continue loopaddr; - } else { - int swlen = (int) (endOffset - startOffset); - actualOperands[0] = swlen; - for (int c = 2; c < actualOperands.length; c++) { - actualOperands[c] = swlen; - } - } - } - - } else { - break; // Unknown instructions are ignored (Some of the obfuscators add unknown instructions) - //throw new UnknownInstructionCode(instructionCode); - } - } finally { - if (instr == null) { - ais.endDumpLevel(); - } else { - ais.endDumpLevel(instr.instructionCode); - } - } - } - } catch (EndOfStreamException ex) { - // lookupswitch obfuscation, ignore - ais.endDumpLevelUntil(diParent); - } - } - - if (diParent != null) { - diParent.sortChildren(); - } - - code = new ArrayList<>(codeMap.size()); - AVM2Instruction prev = null; - for (int i = 0; i < availableBytes; i++) { - AVM2Instruction ins = codeMap.get((long) i); - if (prev != ins) { - code.add(ins); - } - prev = ins; - } - } - - public void compact() { - if (code instanceof ArrayList) { - ((ArrayList) code).trimToSize(); - } - } - - public byte[] getBytes() { - return getBytes(null); - } - - public byte[] getBytes(byte[] origBytes) { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - OutputStream cos; - if ((origBytes != null) && (DEBUG_REWRITE)) { - ByteArrayInputStream origis = new ByteArrayInputStream(origBytes); - cos = new CopyOutputStream(bos, origis); - } else { - cos = bos; - } - try { - for (AVM2Instruction instruction : code) { - cos.write(instruction.getBytes()); - } - } catch (IOException ex) { - } - return bos.toByteArray(); - } - - public void markOffsets() { - long address = 0; - for (int i = 0; i < code.size(); i++) { - code.get(i).setAddress(address); - address += code.get(i).getBytesLength(); - } - } - - @Override - public String toString() { - StringBuilder s = new StringBuilder(); - for (AVM2Instruction instruction : code) { - s.append(instruction.toString()); - s.append(Helper.newLine); - } - return s.toString(); - } - - public String toASMSource() { - return toASMSource(new AVM2ConstantPool()); - } - - public String toASMSource(AVM2ConstantPool constants) { - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); - toASMSource(constants, null, null, null, new ArrayList<>(), ScriptExportMode.PCODE, writer); - return writer.toString(); - } - - public GraphTextWriter toASMSource(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body, ScriptExportMode exportMode, GraphTextWriter writer) { - return toASMSource(constants, trait, info, body, new ArrayList<>(), exportMode, writer); - } - - public GraphTextWriter toASMSource(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body, List outputMap, ScriptExportMode exportMode, GraphTextWriter writer) { - if (trait != null) { - if (trait instanceof TraitFunction) { - TraitFunction tf = (TraitFunction) trait; - writer.appendNoHilight("trait "); - writer.hilightSpecial("function ", HighlightSpecialType.TRAIT_TYPE); - writer.hilightSpecial(constants.multinameToString(tf.name_index), HighlightSpecialType.TRAIT_NAME); - writer.appendNoHilight(" slotid "); - writer.hilightSpecial("" + tf.slot_id, HighlightSpecialType.SLOT_ID); - writer.newLine(); - } - if (trait instanceof TraitMethodGetterSetter) { - TraitMethodGetterSetter tm = (TraitMethodGetterSetter) trait; - writer.appendNoHilight("trait "); - switch (tm.kindType) { - case Trait.TRAIT_METHOD: - writer.hilightSpecial("method ", HighlightSpecialType.TRAIT_TYPE); - break; - case Trait.TRAIT_GETTER: - writer.hilightSpecial("getter ", HighlightSpecialType.TRAIT_TYPE); - break; - case Trait.TRAIT_SETTER: - writer.hilightSpecial("setter ", HighlightSpecialType.TRAIT_TYPE); - break; - } - writer.hilightSpecial(constants.multinameToString(tm.name_index), HighlightSpecialType.TRAIT_NAME); - writer.appendNoHilight(" dispid "); - writer.hilightSpecial("" + tm.disp_id, HighlightSpecialType.DISP_ID); - writer.newLine(); - } - } - - if (info != null) { - writer.appendNoHilight("method").newLine(); - writer.appendNoHilight("name "); - writer.hilightSpecial(info.name_index == 0 ? "null" : "\"" + Helper.escapeActionScriptString(info.getName(constants)) + "\"", HighlightSpecialType.METHOD_NAME); - writer.newLine(); - if (info.flagExplicit()) { - writer.appendNoHilight("flag "); - writer.hilightSpecial("EXPLICIT", HighlightSpecialType.FLAG_EXPLICIT); - writer.newLine(); - } - if (info.flagHas_optional()) { - writer.appendNoHilight("flag "); - writer.hilightSpecial("HAS_OPTIONAL", HighlightSpecialType.FLAG_HAS_OPTIONAL); - writer.newLine(); - writer.appendNoHilight("flag HAS_OPTIONAL").newLine(); - } - if (info.flagHas_paramnames()) { - writer.appendNoHilight("flag "); - writer.hilightSpecial("HAS_PARAM_NAMES", HighlightSpecialType.FLAG_HAS_PARAM_NAMES); - writer.newLine(); - } - if (info.flagIgnore_rest()) { - writer.appendNoHilight("flag "); - writer.hilightSpecial("EXPLICIT", HighlightSpecialType.FLAG_IGNORE_REST); - writer.newLine(); - } - if (info.flagNeed_activation()) { - writer.appendNoHilight("flag "); - writer.hilightSpecial("NEED_ACTIVATION", HighlightSpecialType.FLAG_NEED_ACTIVATION); - writer.newLine(); - } - if (info.flagNeed_arguments()) { - writer.appendNoHilight("flag "); - writer.hilightSpecial("NEED_ARGUMENTS", HighlightSpecialType.FLAG_NEED_ARGUMENTS); - writer.newLine(); - } - if (info.flagNeed_rest()) { - writer.appendNoHilight("flag "); - writer.hilightSpecial("NEED_REST", HighlightSpecialType.FLAG_NEED_REST); - writer.newLine(); - } - if (info.flagSetsdxns()) { - writer.appendNoHilight("flag "); - writer.hilightSpecial("SET_DXNS", HighlightSpecialType.FLAG_SET_DXNS); - writer.newLine(); - } - for (int p = 0; p < info.param_types.length; p++) { - writer.appendNoHilight("param "); - writer.hilightSpecial(constants.multinameToString(info.param_types[p]), HighlightSpecialType.PARAM, p); - writer.newLine(); - } - if (info.flagHas_paramnames()) { - for (int n : info.paramNames) { - writer.appendNoHilight("paramname "); - if (n == 0) { - writer.appendNoHilight("null"); - } else { - writer.appendNoHilight("\""); - writer.appendNoHilight(constants.getString(n)); - writer.appendNoHilight("\""); - } - writer.newLine(); - } - } - if (info.flagHas_optional()) { - for (int i = 0; i < info.optional.length; i++) { - ValueKind vk = info.optional[i]; - writer.appendNoHilight("optional "); - writer.hilightSpecial(vk.toString(constants), HighlightSpecialType.OPTIONAL, i); - writer.newLine(); - } - } - writer.appendNoHilight("returns "); - writer.hilightSpecial(constants.multinameToString(info.ret_type), HighlightSpecialType.RETURNS); - writer.newLine(); - } - writer.newLine(); - - Set importantOffsets = getImportantOffsets(body, true); - if (body != null) { - writer.appendNoHilight("body").newLine(); - - writer.appendNoHilight("maxstack "); - writer.appendNoHilight(body.max_stack); - writer.newLine(); - - writer.appendNoHilight("localcount "); - writer.appendNoHilight(body.max_regs); - writer.newLine(); - - writer.appendNoHilight("initscopedepth "); - writer.appendNoHilight(body.init_scope_depth); - writer.newLine(); - - writer.appendNoHilight("maxscopedepth "); - writer.appendNoHilight(body.max_scope_depth); - writer.newLine(); - - for (int e = 0; e < body.exceptions.length; e++) { - ABCException exception = body.exceptions[e]; - writer.appendNoHilight("try"); - - writer.appendNoHilight(" from "); - writer.appendNoHilight("ofs"); - writer.appendNoHilight(Helper.formatAddress(exception.start)); - - writer.appendNoHilight(" to "); - writer.appendNoHilight("ofs"); - writer.appendNoHilight(Helper.formatAddress(exception.end)); - - writer.appendNoHilight(" target "); - writer.appendNoHilight("ofs"); - writer.appendNoHilight(Helper.formatAddress(exception.target)); - - writer.appendNoHilight(" type "); - writer.hilightSpecial(exception.type_index == 0 ? "null" : constants.getMultiname(exception.type_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_TYPE, e); - - writer.appendNoHilight(" name "); - writer.hilightSpecial(exception.name_index == 0 ? "null" : constants.getMultiname(exception.name_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_NAME, e); - writer.newLine(); - } - } - - writer.newLine(); - writer.appendNoHilight("code").newLine(); - - int ip = 0; - int largeLimit = 20000; - boolean markOffsets = code.size() <= largeLimit; - - if (exportMode == ScriptExportMode.HEX) { - Helper.byteArrayToHexWithHeader(writer, getBytes()); - } else if (exportMode == ScriptExportMode.PCODE || exportMode == ScriptExportMode.PCODE_HEX) { - for (AVM2Instruction ins : code) { - long addr = ins.getAddress(); - if (exportMode == ScriptExportMode.PCODE_HEX) { - writer.appendNoHilight("; "); - writer.appendNoHilight(Helper.bytesToHexString(ins.getBytes())); - writer.newLine(); - } - if (Configuration.showAllAddresses.get() || importantOffsets.contains(addr)) { - writer.appendNoHilight("ofs" + Helper.formatAddress(addr) + ":"); - } - /*for (int e = 0; e < body.exceptions.length; e++) { - if (body.exceptions[e].start == ofs) { - ret.append("exceptionstart " + e + ":"); - } - if (body.exceptions[e].end == ofs) { - ret.append("exceptionend " + e + ":"); - } - if (body.exceptions[e].target == ofs) { - ret.append("exceptiontarget " + e + ":"); - } - }*/ - - if (!ins.isIgnored()) { - if (markOffsets) { - writer.append("", addr, ins.getFileOffset()); - } - - writer.appendNoHilight(ins.toStringNoAddress(constants, new ArrayList<>())); - writer.newLine(); - outputMap.add(ip); - } - - ip++; - } - } else if (exportMode == ScriptExportMode.CONSTANTS) { - writer.appendNoHilight("Constant export mode is not supported.").newLine(); - } - - return writer; - } - - public Set getImportantOffsets(MethodBody body, boolean tryEnds) { - Set ret = new HashSet<>(); - if (body != null) { - for (ABCException exception : body.exceptions) { - ret.add((long) exception.start); - if (tryEnds) { - ret.add((long) exception.end); - } - ret.add((long) exception.target); - } - } - - for (AVM2Instruction ins : code) { - ret.addAll(ins.getOffsets()); - } - - return ret; - } - - public AVM2Instruction adr2ins(long address) throws ConvertException { - int pos = adr2pos(address, false); - if (pos == code.size()) { - // end - return null; - } - - return code.get(pos); - } - - public int adr2pos(long address) throws ConvertException { - return adr2pos(address, false); - } - - public int adr2pos(long address, boolean nearest) throws ConvertException { - int ret = adr2posNoEx(address); - if (ret < 0) { - if (nearest && address < getEndOffset()) { - return -ret - 1; - } - throw new ConvertException("Invalid jump to ofs" + Helper.formatAddress(address), -1); - } - return ret; - } - - private int adr2posNoEx(long address) { - int min = 0; - int max = code.size() - 1; - - while (max >= min) { - int mid = (min + max) / 2; - long midValue = code.get(mid).getAddress(); - if (midValue == address) { - return mid; - } else if (midValue < address) { - min = mid + 1; - } else { - max = mid - 1; - } - } - - if (address == getEndOffset()) { - return code.size(); - } - - return -min - 1; - } - - public long pos2adr(int pos) { - if (pos == code.size()) { - return getEndOffset(); - } - return (int) code.get(pos).getAddress(); - } - - public long getEndOffset() { - if (code.isEmpty()) { - return 0; - } - - AVM2Instruction ins = code.get(code.size() - 1); - return (int) (ins.getAddress() + ins.getBytesLength()); - } - - /** - * Test for killed register. CalcKilledStats must be called before - * - * @param regName - * @param start - * @param end - * @return - */ - public boolean isKilled(int regName, int start, int end) { - if (!killedRegs.containsKey(regName)) { - return false; - } - for (int ip : killedRegs.get(regName)) { - if (ip >= start && ip <= end) { - return true; - } - } - return false; - } - - private int toSourceCount = 0; - - public Map getLocalRegNamesFromDebug(ABC abc) { - Map localRegNames = new HashMap<>(); - - for (AVM2Instruction ins : code) { - if (ins.definition instanceof DebugIns) { - if (ins.operands[0] == 1) { - String v = abc.constants.getString(ins.operands[1]); - // Same name already exists, it may be wrong names inserted by obfuscator - if (localRegNames.values().contains(v)) { - return new HashMap<>(); - } - localRegNames.put(ins.operands[2] + 1, v); - } - } - } - - // TODO: Make this immune to using existing multinames (?) - return localRegNames; - } - - private Map> killedRegs = new HashMap<>(); - - public void calcKilledStats(MethodBody body) throws InterruptedException { - killedRegs.clear(); - HashMap> vis = visitCode(body); - - for (int k = 0; k < code.size(); k++) { - if (vis.get(k).isEmpty()) { - continue; - } - if (code.get(k).definition instanceof KillIns) { - int regid = code.get(k).operands[0]; - if (!killedRegs.containsKey(regid)) { - killedRegs.put(regid, new HashSet<>()); - } - killedRegs.get(regid).add(k); - } - } - } - - public List clearTemporaryRegisters(List input) { - List output = new ArrayList<>(input); - for (int i = 0; i < output.size(); i++) { - if (output.get(i) instanceof SetLocalAVM2Item) { - if (isKilled(((SetLocalAVM2Item) output.get(i)).regIndex, 0, code.size() - 1)) { - SetLocalAVM2Item lsi = (SetLocalAVM2Item) output.get(i); - if (i + 1 < output.size()) { - if (output.get(i + 1) instanceof ExitItem) { - GraphTargetItem rv = output.get(i + 1); - if (rv.value instanceof LocalRegAVM2Item) { - LocalRegAVM2Item lr = (LocalRegAVM2Item) rv.value; - if (lr.regIndex == lsi.regIndex) { - rv.value = lsi.value; - } - } - } - } - output.remove(i); - i--; - } - } else if (output.get(i) instanceof WithAVM2Item) { - clearTemporaryRegisters(((WithAVM2Item) output.get(i)).items); - } - } - return output; - } - - public int fixIPAfterDebugLine(int ip) { - if (code.isEmpty()) { - return ip; - } - if (ip >= code.size()) { - return code.size() - 1; - } - while (code.get(ip).definition instanceof DebugLineIns) { - ip++; - } - return ip; - } - - public long fixAddrAfterDebugLine(long addr) throws ConvertException { - return pos2adr(fixIPAfterDebugLine(adr2pos(addr, true))); - } - - public ConvertOutput toSourceOutput(boolean thisHasDefaultToPrimitive, Reference lineStartItem, String path, GraphPart part, boolean processJumps, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, TranslateStack stack, ScopeStack scopeStack, ABC abc, MethodBody body, int start, int end, HashMap localRegNames, List fullyQualifiedNames, boolean[] visited, HashMap localRegAssigmentIps, HashMap> refs) throws ConvertException, InterruptedException { - calcKilledStats(body); - boolean debugMode = DEBUG_MODE; - if (debugMode) { - System.err.println("OPEN SubSource:" + start + "-" + end + " " + code.get(start).toString() + " to " + code.get(end).toString()); - } - if (visited == null) { - visited = new boolean[code.size()]; - } - //if(true) return ""; - toSourceCount++; - if (toSourceLimit > 0 && toSourceCount >= toSourceLimit) { - throw new ConvertException("Limit of subs(" + toSourceLimit + ") was reached", start); - } - List output = new ArrayList<>(); - int ip = start; - //try { - //int addr; - iploop: - while (ip <= end) { - - boolean processTry = processJumps; - //addr = pos2adr(ip); - //int ipfix = fixIPAfterDebugLine(ip); - //int addrfix = pos2adr(ipfix); - //int maxend = -1; - - if (ip > end) { - break; - } - - if (visited[ip]) { - //logger.warning(path + ": Code already visited, ofs:" + Helper.formatAddress(pos2adr(ip)) + ", ip:" + ip); - break; - } - - if (Configuration.simplifyExpressions.get()) { - stack.simplify(); - } - visited[ip] = true; - AVM2Instruction ins = code.get(ip); - if (stack.isEmpty()) { - lineStartItem.setVal(ins); - } - - if (debugMode) { - System.err.println("translating ip " + ip + " ins " + ins.toString() + " stack:" + stack.toString() + " scopeStack:" + scopeStack.toString()); - } - if (ins.definition instanceof NewFunctionIns) { - if (ip + 1 <= end) { - if (code.get(ip + 1).definition instanceof PopIns) { - ip += 2; - continue; - } - } - } - /*if ((ip + 8 < code.size())) { //return in finally clause - if (ins.definition instanceof SetLocalTypeIns) { - if (code.get(ip + 1).definition instanceof PushByteIns) { - AVM2Instruction jmp = code.get(ip + 2); - if (jmp.definition instanceof JumpIns) { - if (jmp.operands[0] == 0) { - if (code.get(ip + 3).definition instanceof LabelIns) { - if (code.get(ip + 4).definition instanceof PopIns) { - if (code.get(ip + 5).definition instanceof LabelIns) { - AVM2Instruction gl = code.get(ip + 6); - if (gl.definition instanceof GetLocalTypeIns) { - if (((GetLocalTypeIns) gl.definition).getRegisterId(gl) == ((SetLocalTypeIns) ins.definition).getRegisterId(ins)) { - AVM2Instruction ki = code.get(ip + 7); - if (ki.definition instanceof KillIns) { - if (ki.operands[0] == ((SetLocalTypeIns) ins.definition).getRegisterId(ins)) { - if (code.get(ip + 8).definition instanceof ReturnValueIns) { - ip = ip + 8; - continue; - } - } - } - } - } - } - } - } - } - } - } - } - }//*/ - - /*if ((ip + 2 < code.size()) && (ins.definition instanceof NewCatchIns)) { // Filling local register in catch clause - if (code.get(ip + 1).definition instanceof DupIns) { - if (code.get(ip + 2).definition instanceof SetLocalTypeIns) { - ins.definition.translate(isStatic, classIndex, localRegs, stack, scopeStack, constants, ins, method_info, output, body, abc, localRegNames, fullyQualifiedNames); - ip += 3; - continue; - } - } - }*/ - if ((ins.definition instanceof GetLocalTypeIns) && (!output.isEmpty()) && (output.get(output.size() - 1) instanceof SetLocalAVM2Item) && (((SetLocalAVM2Item) output.get(output.size() - 1)).regIndex == ((GetLocalTypeIns) ins.definition).getRegisterId(ins)) && isKilled(((SetLocalAVM2Item) output.get(output.size() - 1)).regIndex, start, end)) { - SetLocalAVM2Item slt = (SetLocalAVM2Item) output.remove(output.size() - 1); - stack.push(slt.getValue()); - ip++; - } else if ((ins.definition instanceof SetLocalTypeIns) && (ip + 1 <= end) && (isKilled(((SetLocalTypeIns) ins.definition).getRegisterId(ins), ip, end))) { // set_local_x,get_local_x..kill x - AVM2Instruction insAfter = code.get(ip + 1); - if ((insAfter.definition instanceof GetLocalTypeIns) && (((GetLocalTypeIns) insAfter.definition).getRegisterId(insAfter) == ((SetLocalTypeIns) ins.definition).getRegisterId(ins))) { - GraphTargetItem before = stack.peek(); - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); - stack.push(before); - ip += 2; - continue iploop; - } else { - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); - ip++; - continue iploop; - } - } else if (ins.definition instanceof DupIns) { - int nextPos; - do { - AVM2Instruction insAfter = ip + 1 < code.size() ? code.get(ip + 1) : null; - if (insAfter == null) { - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); - ip++; - break; - } - AVM2Instruction insBefore = ins; - if (ip - 1 >= start) { - insBefore = code.get(ip - 1); - } - if (insAfter.definition instanceof ConvertBIns) { // SWF compiled with debug contain convert_b - ip++; - //addr = pos2adr(ip); - insAfter = code.get(ip + 1); - } - - boolean isAnd; - if (processJumps && (insAfter.definition instanceof IfFalseIns)) { - //stack.add("(" + stack.pop() + ")&&"); - isAnd = true; - } else if (processJumps && (insAfter.definition instanceof IfTrueIns)) { - //stack.add("(" + stack.pop() + ")||"); - isAnd = false; - } else if (insAfter.definition instanceof SetLocalTypeIns) { - // chained assignments - int reg = (((SetLocalTypeIns) insAfter.definition).getRegisterId(insAfter)); - for (int t = ip + 1; t <= end - 1; t++) { - if (code.get(t).definition instanceof KillIns) { - if (code.get(t).operands[0] == reg) { - break; - } - } - if (code.get(t).definition instanceof GetLocalTypeIns) { - if (((GetLocalTypeIns) code.get(t).definition).getRegisterId(code.get(t)) == reg) { - if (code.get(t + 1).definition instanceof KillIns) { - if (code.get(t + 1).operands[0] == reg) { - ConvertOutput assignment = toSourceOutput(thisHasDefaultToPrimitive, lineStartItem, path, part, processJumps, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, abc, body, ip + 2, t - 1, localRegNames, fullyQualifiedNames, visited, localRegAssigmentIps, refs); - if (!assignment.output.isEmpty()) { - GraphTargetItem tar = assignment.output.remove(assignment.output.size() - 1); - tar.firstPart = part; - stack.push(tar); - ip = t + 2; - - continue iploop; - } - } - } - } - } - } - if (!isKilled(reg, 0, end)) { - GraphTargetItem vx = stack.pop().getThroughDuplicate(); - int dupCnt = 1; - for (int i = ip - 1; i >= start; i--) { - if (code.get(i).definition instanceof DupIns) { - if (stack.isEmpty()) { - break; // FIXME?o - } - stack.pop(); - dupCnt++; - //stack.push(v); - } else { - break; - } - } - for (int i = 0; i < dupCnt; i++) { - stack.push(new LocalRegAVM2Item(ins, (AVM2Instruction) lineStartItem.getVal(), reg, vx)); - } - stack.push(vx); - } else { - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); - } - ip++; - break; - //} - - } else { - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); - ip++; - break; - //throw new ConvertException("Unknown pattern after DUP:" + insComparsion.toString()); - } - } while (ins.definition instanceof DupIns); - } else if ((ins.definition instanceof ReturnValueIns) || (ins.definition instanceof ReturnVoidIns) || (ins.definition instanceof ThrowIns)) { - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); - //ip = end + 1; - break; - } else if (ins.definition instanceof NewFunctionIns) { - String functionName = ""; - if ((ip >= start + 2) && (ip <= end - 4)) { - AVM2Instruction prev2 = code.get(ip - 2); - if (prev2.definition instanceof NewObjectIns) { - if (prev2.operands[0] == 0) { - if (code.get(ip - 1).definition instanceof PushWithIns) { - boolean hasDup = false; - int plus = 0; - if (code.get(ip + 1).definition instanceof DupIns) { - hasDup = true; - plus = 1; - } - AVM2Instruction psco = code.get(ip + 1 + plus); - if (psco.definition instanceof GetScopeObjectIns) { - if (psco.operands[0] == scopeStack.size() - 1) { - if (code.get(ip + plus + 2).definition instanceof SwapIns) { - if (code.get(ip + plus + 4).definition instanceof PopScopeIns) { - if (code.get(ip + plus + 3).definition instanceof SetPropertyIns) { - functionName = abc.constants.getMultiname(code.get(ip + plus + 3).operands[0]).getName(abc.constants, fullyQualifiedNames, true); - scopeStack.pop();// with - output.remove(output.size() - 1); // with - ip = ip + plus + 4; // +1 below - } - } - } - } - } - } - } - } - } - // What to do when hasDup is false? - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); - NewFunctionAVM2Item nft = (NewFunctionAVM2Item) stack.peek(); - nft.functionName = functionName; - ip++; - } else { - try { - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); - } catch (RuntimeException re) { - /*String last=""; - int len=5; - for(int i=(ip-len<0?0:ip-len);i maxRegister) { - maxRegister = regId; - } - } - return maxRegister + 1; - } - - public HashMap getLocalRegTypes(AVM2ConstantPool constants, List fullyQualifiedNames) { - HashMap ret = new HashMap<>(); - AVM2Instruction prev = null; - for (AVM2Instruction ins : code) { - if (ins.definition instanceof SetLocalTypeIns) { - if (prev != null) { - if (prev.definition instanceof CoerceOrConvertTypeIns) { - ret.put(((SetLocalTypeIns) ins.definition).getRegisterId(ins), ((CoerceOrConvertTypeIns) prev.definition).getTargetType(constants, prev)); - } - } - } - prev = ins; - } - return ret; - - } - - private class Slot { - - public final GraphTargetItem scope; - - public final Multiname multiname; - - public Slot(GraphTargetItem scope, Multiname multiname) { - this.scope = scope; - this.multiname = multiname; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Slot) { - Slot slot = (Slot) obj; - return (slot.scope.getThroughRegister() == scope.getThroughRegister()) - && (slot.multiname == multiname); - } - return false; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 59 * hash + (scope != null ? Objects.hashCode(scope.getThroughRegister()) : 0); - hash = 59 * hash + Objects.hashCode(multiname); - return hash; - } - } - - public void initToSource() { - toSourceCount = 0; - } - - private GraphTargetItem handleDeclareReg(int minreg, GraphTargetItem assignment, DeclarationAVM2Item[] declaredRegisters, List declaredSlots, int reg) { - - //do not add declarations for reserved local registers like function arguments - if (reg < minreg) { - return assignment; - } - GraphTargetItem vtype = TypeItem.UNBOUNDED; - if (assignment.value instanceof ConvertAVM2Item) { - vtype = ((ConvertAVM2Item) assignment.value).type; - } - - if (vtype.equals(TypeItem.UNBOUNDED) && (assignment.value instanceof CoerceAVM2Item)) { - vtype = ((CoerceAVM2Item) assignment.value).typeObj; - } - if (vtype.equals(TypeItem.UNBOUNDED) && (assignment.value instanceof SimpleValue) && ((SimpleValue) assignment.value).isSimpleValue()) { - vtype = assignment.value.returnType(); - } - - if (declaredRegisters[reg] == null) { - declaredRegisters[reg] = new DeclarationAVM2Item(assignment, vtype); - if (assignment instanceof SetTypeAVM2Item) { - ((SetTypeAVM2Item) assignment).setDeclaration(declaredRegisters[reg]); - } - return declaredRegisters[reg]; - } - - if (declaredRegisters[reg].type == TypeItem.UNBOUNDED) { - - } else if (!declaredRegisters[reg].type.equals(vtype)) { //already declared with different type - declaredRegisters[reg].type = TypeItem.UNBOUNDED; - } - - if (assignment instanceof SetTypeAVM2Item) { - ((SetTypeAVM2Item) assignment).setDeclaration(declaredRegisters[reg]); - } - - return assignment; - } - - private GraphTargetItem injectDeclarations(int minreg, GraphTargetItem ti, DeclarationAVM2Item[] declaredRegisters, List declaredSlots, List declaredSlotsDec, ABC abc, MethodBody body) { - if (ti.value != null) { - ti.value = injectDeclarations(minreg, ti.value, declaredRegisters, declaredSlots, declaredSlotsDec, abc, body); - } - //TODO: walk whole tree... some walker? - if (ti instanceof IfItem) { - ((IfItem) ti).expression = injectDeclarations(minreg, ((IfItem) ti).expression, declaredRegisters, declaredSlots, declaredSlotsDec, abc, body); - } - if (ti instanceof BinaryOpItem) { - ((BinaryOpItem) ti).leftSide = injectDeclarations(minreg, ((BinaryOpItem) ti).leftSide, declaredRegisters, declaredSlots, declaredSlotsDec, abc, body); - ((BinaryOpItem) ti).rightSide = injectDeclarations(minreg, ((BinaryOpItem) ti).rightSide, declaredRegisters, declaredSlots, declaredSlotsDec, abc, body); - } - if (ti instanceof ForEachInAVM2Item) { - ForEachInAVM2Item fei = (ForEachInAVM2Item) ti; - if (fei.expression.object instanceof LocalRegAVM2Item) { - int reg = ((LocalRegAVM2Item) fei.expression.object).regIndex; - if (declaredRegisters[reg] == null) { - fei.expression.object = handleDeclareReg(minreg, fei.expression.object, declaredRegisters, declaredSlots, reg); - } - } - } - if (ti instanceof ForInAVM2Item) { - ForInAVM2Item fi = (ForInAVM2Item) ti; - if (fi.expression.object instanceof LocalRegAVM2Item) { - int reg = ((LocalRegAVM2Item) fi.expression.object).regIndex; - fi.expression.object = handleDeclareReg(minreg, fi.expression.object, declaredRegisters, declaredSlots, reg); - //nowdeclaredRegs.add(reg); - - } - } - if (ti instanceof Block) { - Block bl = (Block) ti; - for (List s : bl.getSubs()) { - injectDeclarations(minreg, s, declaredRegisters, declaredSlots, declaredSlotsDec, abc, body); - } - } - if (ti instanceof SetLocalAVM2Item) { - int reg = ((SetLocalAVM2Item) ti).regIndex; - ti = handleDeclareReg(minreg, ti, declaredRegisters, declaredSlots, reg); - return ti; - } - if (ti instanceof SetSlotAVM2Item) { - SetSlotAVM2Item ssti = (SetSlotAVM2Item) ti; - Slot sl = new Slot(ssti.scope, ssti.slotName); - if (!declaredSlots.contains(sl)) { - GraphTargetItem type = TypeItem.UNBOUNDED; - for (int t = 0; t < body.traits.traits.size(); t++) { - if (body.traits.traits.get(t).getName(abc) == sl.multiname) { - if (body.traits.traits.get(t) instanceof TraitSlotConst) { - type = PropertyAVM2Item.multinameToType(((TraitSlotConst) body.traits.traits.get(t)).type_index, abc.constants); - } - } - } - DeclarationAVM2Item d = new DeclarationAVM2Item(ti, type); - ssti.setDeclaration(d); - declaredSlotsDec.add(d); - declaredSlots.add(sl); - return d; - //nowdeclaredSlots.add(sl); - } else { - int idx = declaredSlots.indexOf(sl); - ssti.setDeclaration(declaredSlotsDec.get(idx)); - } - } - return ti; - } - - private void injectDeclarations(int minreg, List list, DeclarationAVM2Item[] declaredRegisters, List declaredSlots, List declaredSlotsDec, ABC abc, MethodBody body) { - //List nowdeclaredRegs=new ArrayList<>(); - //List nowdeclaredSlots=new ArrayList<>(); - for (int i = 0; i < list.size(); i++) { - GraphTargetItem ti = list.get(i); - GraphTargetItem ti2 = injectDeclarations(minreg, ti, declaredRegisters, declaredSlots, declaredSlotsDec, abc, body); - if (ti != ti2) { - list.set(i, ti2); - } - } - - /* - //undeclare registers at the end of the block? - for(int reg:nowdeclaredRegs){ - declaredRegisters[reg] = false; - } - - for(Slot s:nowdeclaredSlots){ - declaredSlots.remove(s); - }*/ - } - - public List toGraphTargetItems(boolean thisHasDefaultToPrimitive, ConvertData convertData, String path, int methodIndex, boolean isStatic, int scriptIndex, int classIndex, ABC abc, MethodBody body, HashMap localRegNames, ScopeStack scopeStack, int initializerType, List fullyQualifiedNames, List initTraits, int staticOperation, HashMap localRegAssigmentIps, HashMap> refs) throws InterruptedException { - initToSource(); - List list; - HashMap localRegs = new HashMap<>(); - - int regCount = getRegisterCount(); - for (int i = 0; i < regCount; i++) { - localRegs.put(0, new UndefinedAVM2Item(null, null)); - } - - //try { - list = AVM2Graph.translateViaGraph(path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs, thisHasDefaultToPrimitive); - - if (initTraits != null) { - loopi: - for (int i = 0; i < list.size(); i++) { - GraphTargetItem ti = list.get(i); - if ((ti instanceof InitPropertyAVM2Item) || (ti instanceof SetPropertyAVM2Item)) { - int multinameIndex = 0; - GraphTargetItem value = null; - if (ti instanceof InitPropertyAVM2Item) { - multinameIndex = ((InitPropertyAVM2Item) ti).propertyName.multinameIndex; - value = ((InitPropertyAVM2Item) ti).value; - } - if (ti instanceof SetPropertyAVM2Item) { - multinameIndex = ((FullMultinameAVM2Item) ((SetPropertyAVM2Item) ti).propertyName).multinameIndex; - value = ((SetPropertyAVM2Item) ti).value; - } - Multiname m = abc.constants.getMultiname(multinameIndex); - for (Traits ts : initTraits) { - for (Trait t : ts.traits) { - Multiname tm = abc.constants.getMultiname(t.name_index); - if (tm != null && tm.equals(m)) { - if ((t instanceof TraitSlotConst)) { - if (((TraitSlotConst) t).isConst() || initializerType == GraphTextWriter.TRAIT_CLASS_INITIALIZER || initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) { - TraitSlotConst tsc = (TraitSlotConst) t; - if (value != null && !convertData.assignedValues.containsKey(tsc)) { - - if (value instanceof NewFunctionAVM2Item) { - NewFunctionAVM2Item f = (NewFunctionAVM2Item) value; - f.functionName = tsc.getName(abc).getName(abc.constants, fullyQualifiedNames, true); - } - AssignedValue av = new AssignedValue(value, initializerType, methodIndex); - convertData.assignedValues.put(tsc, av); - list.remove(i); - i--; - continue; - } - } - break; - } - } - } - } - } else { - // In obfuscated code, SetLocal instructions comes first - //break; - } - } - } - if (initializerType == GraphTextWriter.TRAIT_CLASS_INITIALIZER || initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) { - List newList = new ArrayList<>(); - for (GraphTargetItem ti : list) { - if (!(ti instanceof ReturnVoidAVM2Item)) { - if (!(ti instanceof InitPropertyAVM2Item)) { - newList.add(ti); - } - } - } - list = newList; - if (list.isEmpty()) { - return list; - } - } - // Declarations - - DeclarationAVM2Item d[] = new DeclarationAVM2Item[regCount]; - - int param_types[] = abc.method_info.get(body.method_info).param_types; - int r = 1; - for (int i = 0; i < param_types.length; i++) { - GraphTargetItem type; - if (param_types[i] == 0) { - type = TypeItem.UNBOUNDED; - } else { - type = new TypeItem(abc.constants.getMultiname(param_types[i]).getNameWithNamespace(abc.constants)); - } - if (d.length > r) { - d[r] = new DeclarationAVM2Item(new SetLocalAVM2Item(null, null, r, new NullAVM2Item(null, null)), type); - } - r++; - } - if (abc.method_info.get(body.method_info).flagNeed_arguments()) { - if (d.length > r) { - d[r] = new DeclarationAVM2Item(new SetLocalAVM2Item(null, null, r, new NullAVM2Item(null, null)), TypeItem.ARRAY /*?*/); - } - r++; - } - if (abc.method_info.get(body.method_info).flagNeed_rest()) { - if (d.length > r) { - d[r] = new DeclarationAVM2Item(new SetLocalAVM2Item(null, null, r, new NullAVM2Item(null, null)), TypeItem.ARRAY/*?*/); - } - r++; - } - // - - //int minreg = abc.method_info.get(body.method_info).getMaxReservedReg() + 1; - injectDeclarations(1, list, d, new ArrayList<>(), new ArrayList<>(), abc, body); - - int lastPos = list.size() - 1; - if (lastPos < 0) { - lastPos = 0; - } - if ((list.size() > lastPos) && (list.get(lastPos) instanceof ScriptEndItem)) { - lastPos--; - } - if (lastPos < 0) { - lastPos = 0; - } - if ((list.size() > lastPos) && (list.get(lastPos) instanceof ReturnVoidAVM2Item)) { - list.remove(lastPos); - } - - return list; - } - - public void updateOffsets(OffsetUpdater updater, MethodBody body) { - for (int i = 0; i < code.size(); i++) { - AVM2Instruction ins = code.get(i); - if (ins.definition instanceof LookupSwitchIns) { - long target = ins.getAddress() + ins.operands[0]; - ins.operands[0] = updater.updateOperandOffset(ins.getAddress(), target, ins.operands[0]); - for (int k = 2; k < ins.operands.length; k++) { - target = ins.getAddress() + ins.operands[k]; - ins.operands[k] = updater.updateOperandOffset(ins.getAddress(), target, ins.operands[k]); - } - } else /*for (int j = 0; j < ins.definition.operands.length; j++) { - if (ins.definition.operands[j] == AVM2Code.DAT_OFFSET) { - long target = ins.offset + ins.getBytes().length + ins.operands[j]; - ins.operands[j] = updater.updateOperandOffset(target, ins.operands[j]); - } - }*/ //Faster, but not so universal - { - if (ins.definition instanceof IfTypeIns) { - long target = ins.getTargetAddress(); - try { - ins.operands[0] = updater.updateOperandOffset(ins.getAddress(), target, ins.operands[0]); - } catch (ConvertException cex) { - throw new ConvertException("Invalid offset (" + ins + ")", i); - } - } - } - ins.setAddress(updater.updateInstructionOffset(ins.getAddress())); - } - - for (ABCException ex : body.exceptions) { - ex.start = updater.updateOperandOffset(-1, ex.start, ex.start); - ex.end = updater.updateOperandOffset(-1, ex.end, ex.end); - ex.target = updater.updateOperandOffset(-1, ex.target, ex.target); - } - } - - public void fixJumps(final String path, MethodBody body) throws InterruptedException { - if (code.isEmpty()) { - return; - } - final List insAddrToRemove = new ArrayList<>(); - final long endOffset = getEndOffset(); - updateOffsets(new OffsetUpdater() { - - @Override - public long updateInstructionOffset(long address) { - return address; - } - - @Override - public int updateOperandOffset(long insAddr, long targetAddress, int offset) { - if (targetAddress > endOffset || targetAddress < 0 || adr2posNoEx(targetAddress) < 0) { - insAddrToRemove.add(insAddr); - } - return offset; - } - - }, body); - - boolean someIgnored = false; - for (Long insAddr : insAddrToRemove) { - int pos = adr2posNoEx(insAddr); - if (pos > -1) { - code.get(pos).setIgnored(true, 0); - someIgnored = true; - } - } - if (someIgnored) { - logger.log(Level.WARNING, path + ": One or more invalid jump offsets found in the code. Those instructions were ignored."); - } - removeIgnored(body); - } - - public void checkValidOffsets(MethodBody body) { - updateOffsets(new OffsetUpdater() { - - @Override - public long updateInstructionOffset(long address) { - adr2pos(address); - return address; - } - - @Override - public int updateOperandOffset(long insAddr, long targetAddress, int offset) { - /*if (insAddr == -1) { - return offset; - }*/ - adr2pos(targetAddress); - return offset; - } - - }, body); - } - - public void removeInstruction(int pos, MethodBody body) { - if ((pos < 0) || (pos >= code.size())) { - throw new IndexOutOfBoundsException(); - } - - AVM2Instruction ins = code.get(pos); - final long remOffset = ins.getAddress(); - int bc = ins.getBytesLength(); - - final int byteCount = bc; - updateOffsets(new OffsetUpdater() { - @Override - public long updateInstructionOffset(long address) { - if (address > remOffset) { - return address - byteCount; - } - return address; - } - - @Override - public int updateOperandOffset(long jumpInsAddr, long jumpTargetAddr, int jumpOffset) { - /* - a:jump d: - b: - c:X - d: - */ - if (jumpTargetAddr > remOffset && jumpInsAddr < remOffset) { - return jumpOffset - byteCount; - } - /* - a:X1 - b:X2 - c: - d:jump a: - */ - if (jumpTargetAddr <= remOffset && jumpInsAddr > remOffset) { - return jumpOffset + byteCount; - } - - return jumpOffset; - } - }, body); - code.remove(pos); - //checkValidOffsets(body); - } - - /** - * Inserts instruction at specified point. Handles offsets properly. Note: - * If newinstruction is jump, the offset operand must be handled properly by - * caller. All old jump offsets to pos are targeted before new instruction. - * - * @param pos Position in the list - * @param instruction Instruction False means before new instruction - * @param body Method body (used for try handling) - */ - public void insertInstruction(int pos, AVM2Instruction instruction, MethodBody body) { - insertInstruction(pos, instruction, false, body); - } - - /** - * Replaces instruction by another. Properly handles offsets. Note: If - * newinstruction is jump, the offset operand must be handled properly by - * caller. - * - * @param pos - * @param instruction - * @param body - */ - public void replaceInstruction(int pos, AVM2Instruction instruction, MethodBody body) { - AVM2Instruction oldInstruction = code.get(pos); - instruction.setAddress(oldInstruction.getAddress()); - int oldByteCount = oldInstruction.getBytesLength(); - int newByteCount = instruction.getBytesLength(); - int byteDelta = newByteCount - oldByteCount; - - if (byteDelta != 0) { - updateOffsets(new OffsetUpdater() { - - @Override - public long updateInstructionOffset(long address) { - if (address > instruction.getAddress()) { - return address + byteDelta; - } - return address; - } - - @Override - public int updateOperandOffset(long insAddr, long targetAddress, int offset) { - if (targetAddress > instruction.getAddress() && insAddr <= instruction.getAddress()) { - return offset + byteDelta; - } - if (targetAddress <= instruction.getAddress() && insAddr > instruction.getAddress()) { - return offset - byteDelta; - } - return offset; - } - }, body); - } - code.set(pos, instruction); - } - - /** - * Inserts instruction at specified point. Handles offsets properly. Note: - * If newinstruction is jump, the offset operand must be handled properly by - * caller. - * - * @param pos Position in the list - * @param instruction Instruction - * @param mapOffsetsAfterIns Map all jumps to the pos after new instruction? - * False means before new instruction - * @param body Method body (used for try handling) - */ - public void insertInstruction(int pos, AVM2Instruction instruction, boolean mapOffsetsAfterIns, MethodBody body) { - //checkValidOffsets(body); - if (pos < 0) { - pos = 0; - } - if (pos > code.size()) { - pos = code.size(); - } - final int byteCount = instruction.getBytesLength(); - if (pos == code.size()) { - instruction.setAddress(code.get(pos - 1).getAddress() + code.get(pos - 1).getBytesLength()); - } else { - instruction.setAddress(code.get(pos).getAddress()); - } - final long x = instruction.getAddress(); - updateOffsets(new OffsetUpdater() { - - @Override - public long updateInstructionOffset(long offset) { - if (offset >= x) { - return offset + byteCount; - } - return offset; - } - - @Override - public int updateOperandOffset(long j, long t, int offset_jt) { - - /* - j:jump t: - n: - n: - x:# - t: - */ - if (((t > x) || (mapOffsetsAfterIns && (t == x))) && (j < x)) { - return offset_jt + byteCount; - } - /* - t: - x:# - n: - n: - j:jump t: - */ - if (((t < x) || (mapOffsetsAfterIns && (t == x))) && (j > x)) { - return offset_jt - byteCount; - } - - /* - t: - n: - n: - j:x: # jump t: - */ - if ((j == x) && (t < x)) { - return offset_jt - byteCount; - } - - return offset_jt; - } - }, body); - instruction.setAddress(x); - code.add(pos, instruction); - //checkValidOffsets(body); - } - - public int removeTraps(Trait trait, int methodInfo, MethodBody body, ABC abc, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException { - SWFDecompilerPlugin.fireAvm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); - try (Statistics s = new Statistics("AVM2DeobfuscatorGetSet")) { - new AVM2DeobfuscatorGetSet().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); - } - try (Statistics s = new Statistics("AVM2DeobfuscatorSimple")) { - new AVM2DeobfuscatorSimpleOld().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); - } - try (Statistics s = new Statistics("AVM2DeobfuscatorRegisters")) { - new AVM2DeobfuscatorRegistersOld().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); - } - try (Statistics s = new Statistics("AVM2DeobfuscatorJumps")) { - new AVM2DeobfuscatorJumps().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); - } - return 1; - } - - private void handleRegister(CodeStats stats, int reg) { - if (reg + 1 > stats.maxlocal) { - stats.maxlocal = reg + 1; - } - } - - private boolean walkCode(CodeStats stats, int pos, int stack, int scope, ABC abc) { - while (pos < code.size()) { - AVM2Instruction ins = code.get(pos); - if (stats.instructionStats[pos].seen) { - // check stack mismatch here - return true; - } - - if (ins.definition instanceof NewFunctionIns) { - MethodBody innerBody = abc.findBody(ins.operands[0]); - innerBody.autoFillStats(abc, stats.initscope + (stats.has_activation ? 1 : 0), false); - } - - stats.instructionStats[pos].seen = true; - stats.instructionStats[pos].stackpos = stack; - stats.instructionStats[pos].scopepos = scope; - - int stackDelta = ins.definition.getStackDelta(ins, abc); - int scopeDelta = ins.definition.getScopeStackDelta(ins, abc); - int oldStack = stack; - - //+" deltaScope:"+(scopeDelta>0?"+"+scopeDelta:scopeDelta)+" stack:"+stack+" scope:"+scope); - stack += stackDelta; - scope += scopeDelta; - - stats.instructionStats[pos].stackpos_after = stack; - stats.instructionStats[pos].scopepos_after = scope; - - if (stack > stats.maxstack) { - stats.maxstack = stack; - } - if (scope > stats.maxscope) { - stats.maxscope = scope; - } - - //System.out.println("stack "+oldStack+(stackDelta>=0?"+"+stackDelta:stackDelta)+" max:"+stats.maxstack+" "+ins); - if ((ins.definition instanceof DXNSIns) || (ins.definition instanceof DXNSLateIns)) { - stats.has_set_dxns = true; - } - if (ins.definition instanceof NewActivationIns) { - stats.has_activation = true; - } - if (ins.definition instanceof SetLocalTypeIns) { - handleRegister(stats, ((SetLocalTypeIns) ins.definition).getRegisterId(ins)); - } else if (ins.definition instanceof GetLocalTypeIns) { - handleRegister(stats, ((GetLocalTypeIns) ins.definition).getRegisterId(ins)); - } else { - for (int i = 0; i < ins.definition.operands.length; i++) { - int op = ins.definition.operands[i]; - if (op == DAT_LOCAL_REG_INDEX) { - handleRegister(stats, ins.operands[i]); - } - } - } - if (ins.definition instanceof ReturnValueIns) { - // check stack=1 - return true; - } - if (ins.definition instanceof ReturnVoidIns) { - // check stack=0 - return true; - } - if (ins.definition instanceof JumpIns) { - try { - pos = adr2pos(ins.getTargetAddress()); - continue; - } catch (ConvertException ex) { - return false; - } - } else if (ins.definition instanceof IfTypeIns) { - try { - int newpos = adr2pos(ins.getTargetAddress()); - walkCode(stats, newpos, stack, scope, abc); - } catch (ConvertException ex) { - return false; - } - } - if (ins.definition instanceof LookupSwitchIns) { - for (int i = 0; i < ins.operands.length; i++) { - if (i == 1) { - continue; - } - try { - int newpos = adr2pos(pos2adr(pos) + ins.operands[i]); - if (!walkCode(stats, newpos, stack, scope, abc)) { - return false; - } - } catch (ConvertException ex) { - return false; - } - } - } - pos++; - } - return true; - } - - public CodeStats getStats(ABC abc, MethodBody body, int initScope) { - CodeStats stats = new CodeStats(this); - stats.initscope = initScope; - if (!walkCode(stats, 0, 0, initScope, abc)) { - return null; - } - int scopePos = -1; - int prevStart = 0; - for (int e = 0; e < body.exceptions.length; e++) { - ABCException ex = body.exceptions[e]; - try { - if (scopePos == -1) { - scopePos = stats.instructionStats[adr2pos(ex.end) - 1].scopepos_after; - } - List visited = new ArrayList<>(); - for (int i = 0; i < stats.instructionStats.length; i++) { - if (stats.instructionStats[i].seen) { - visited.add(i); - } - } - if (!walkCode(stats, adr2pos(ex.target), 1 + (ex.isFinally() ? 1 : 0), scopePos, abc)) { - return null; - } - int maxIp = 0; - // searching for visited instruction in second run which has maximum position - for (int i = 0; i < stats.instructionStats.length; i++) { - if (stats.instructionStats[i].seen && !visited.contains(i)) { - maxIp = i; - } - } - scopePos = stats.instructionStats[maxIp].scopepos_after; - int stackPos = stats.instructionStats[maxIp].stackpos_after; - int nextIp = maxIp + 1; - if (code.get(maxIp).definition instanceof JumpIns) { - nextIp = adr2pos(pos2adr(nextIp) + code.get(maxIp).operands[0]); - } - if (nextIp < stats.instructionStats.length) { - InstructionStats nextIpStat = stats.instructionStats[nextIp]; - int origScopePos = nextIpStat.scopepos; - int origStackPos = nextIpStat.stackpos; - - if (prevStart == ex.start && ex.isFinally() && !code.get(nextIp).isExit() && nextIpStat.seen) { - for (int i = 0; i < stats.instructionStats.length; i++) { - stats.instructionStats[i].seen = false; - } - // Rerun rest with new scopePos, stackPos - if (!walkCode(stats, nextIp, origStackPos + 1/*magic!*/, scopePos - 1 /*magic!*/, abc)) { - return null; - } - scopePos--; - } - } - prevStart = ex.start; - } catch (ConvertException ex1) { - // ignore - } - } - //stats.maxscope+=initScope; - return stats; - } - - private void visitCode(int ip, int lastIp, HashMap> refs) throws InterruptedException { - List toVisit = new ArrayList<>(); - List toVisitLast = new ArrayList<>(); - toVisit.add(ip); - toVisitLast.add(lastIp); - while (!toVisit.isEmpty()) { - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException(); - } - ip = toVisit.remove(0); - lastIp = toVisitLast.remove(0); - while (ip < code.size()) { - if (!refs.containsKey(ip)) { - refs.put(ip, new ArrayList<>()); - } - refs.get(ip).add(lastIp); - lastIp = ip; - if (refs.get(ip).size() > 1) { - break; - } - AVM2Instruction ins = code.get(ip); - if (ins.definition instanceof ThrowIns) { - break; - } - if (ins.definition instanceof ReturnValueIns) { - break; - } - if (ins.definition instanceof ReturnVoidIns) { - break; - } - if (ins.definition instanceof LookupSwitchIns) { - try { - for (int i = 2; i < ins.operands.length; i++) { - toVisit.add(adr2pos(pos2adr(ip) + ins.operands[i])); - toVisitLast.add(ip); - } - ip = adr2pos(pos2adr(ip) + ins.operands[0]); - continue; - } catch (ConvertException ex) { - } - } - if (ins.definition instanceof JumpIns) { - try { - ip = adr2pos(ins.getTargetAddress()); - continue; - } catch (ConvertException ex) { - logger.log(Level.FINE, null, ex); - } - } else if (ins.definition instanceof IfTypeIns) { - try { - toVisit.add(adr2pos(ins.getTargetAddress())); - toVisitLast.add(ip); - } catch (ConvertException ex) { - logger.log(Level.FINE, null, ex); - } - } - ip++; - } - }; - } - - public HashMap> visitCode(MethodBody body) throws InterruptedException { - HashMap> refs = new HashMap<>(); - for (int i = 0; i < code.size(); i++) { - refs.put(i, new ArrayList<>()); - } - visitCode(0, 0, refs); - int pos = 0; - for (ABCException e : body.exceptions) { - pos++; - try { - visitCode(adr2pos(e.start, true), adr2pos(e.start, true) - 1, refs); - visitCode(adr2pos(e.start, true), -1, refs); - visitCode(adr2pos(e.target), adr2pos(e.end, true), refs); - visitCode(adr2pos(e.end, true), -pos, refs); - } catch (ConvertException ex) { - logger.log(Level.SEVERE, "Visitcode error", ex); - } - } - return refs; - } - - public void removeIgnored(MethodBody body) throws InterruptedException { - //System.err.println("removing ignored..."); - for (int i = 0; i < code.size(); i++) { - if (code.get(i).isIgnored()) { - removeInstruction(i, body); - i--; - } - } - //System.err.println("/ignored removed"); - } - - public int removeDeadCode(MethodBody body) throws InterruptedException { - HashMap> refs = visitCode(body); - int cnt = 0; - for (int i = code.size() - 1; i >= 0; i--) { - if (refs.get(i).isEmpty()) { - code.get(i).setIgnored(true, 0); - cnt++; - } - } - - removeIgnored(body); - - for (int i = code.size() - 1; i >= 0; i--) { - AVM2Instruction ins = code.get(i); - if (ins.definition instanceof JumpIns) { - if (ins.operands[0] == 0) { - ins.setIgnored(true, 0); - cnt++; - } - } - } - - removeIgnored(body); - - return cnt; - } - - public boolean inlineJumpExit() { - boolean modified = false; - int csize = code.size(); - for (int i = 0; i < csize; i++) { - AVM2Instruction ins = code.get(i); - int insLen = code.get(i).getBytesLength(); - long ofs = pos2adr(i); - if (ins.definition instanceof JumpIns) { - long targetOfs = ofs + insLen + ins.operands[0]; - try { - int ni = adr2pos(targetOfs); - if (ni < code.size() && ni > -1) { - AVM2Instruction ins2 = code.get(ni); - if (ins2.isExit()) { - code.set(i, new AVM2Instruction(ofs, ins2.definition, ins2.operands)); - modified = true; - } - } - } catch (ConvertException ex) { - //ignore - } - } - } - - return modified; - } - - private static int getMostCommonIp(AVM2GraphSource code, List branches) { - List> reachable = new ArrayList<>(); - for (int i = 0; i < branches.size(); i++) { - List r = new ArrayList<>(); - getReachableIps(code, branches.get(i), r); - } - - int commonLevel; - Map levelMap = new HashMap<>(); - for (List first : reachable) { - int maxclevel = 0; - Set visited = new HashSet<>(); - for (Integer p : first) { - if (visited.contains(p)) { - continue; - } - visited.add(p); - boolean common = true; - commonLevel = 1; - for (List r : reachable) { - if (r == first) { - continue; - } - if (r.contains(p)) { - commonLevel++; - } - } - if (commonLevel <= maxclevel) { - continue; - } - maxclevel = commonLevel; - if (levelMap.containsKey(p)) { - if (levelMap.get(p) > commonLevel) { - commonLevel = levelMap.get(p); - } - } - levelMap.put(p, commonLevel); - if (common) { - //return p; - } - } - } - for (int i = reachable.size() - 1; i >= 2; i--) { - for (Integer p : levelMap.keySet()) { - if (levelMap.get(p) == i) { - return p; - } - } - } - for (Integer p : levelMap.keySet()) { - if (levelMap.get(p) == branches.size()) { - return p; - } - } - return -1; - } - - public static void getReachableIps(AVM2GraphSource code, int ip, List reachable) { - do { - if (reachable.contains(ip)) { - return; - } - reachable.add(ip); - GraphSourceItem ins = code.get(ip); - if (ins.isJump() || ins.isBranch()) { - List branches = ins.getBranches(code); - for (int i = 1; i < branches.size(); i++) { - getReachableIps(code, branches.get(i), reachable); - } - ip = branches.get(0); - continue; - } - ip++; - } while (ip < code.size()); - } - - public static boolean isDirectAncestor(int currentIp, int ancestor, HashMap> refs) { - return isDirectAncestor(currentIp, ancestor, refs, new ArrayList<>()); - } - - private static boolean isDirectAncestor(int currentIp, int ancestor, HashMap> refs, List visited) { - if (currentIp == -1) { - return true; - } - do { - if (currentIp == ancestor) { - return true; - } - if (currentIp == 0) { - return false; - } - if (visited.contains(currentIp)) { - return true; - } - visited.add(currentIp); - if (refs.containsKey(currentIp)) { - List currentRefs = refs.get(currentIp); - if ((currentRefs != null) && (!currentRefs.isEmpty())) { - for (int i = 1; i < currentRefs.size(); i++) { - if (!isDirectAncestor(currentRefs.get(i), ancestor, refs, visited)) { - return false; - } - } - currentIp = currentRefs.get(0); - continue; - } - } - currentIp--; - } while (currentIp >= 0); - return false; - } - - public static boolean getPreviousReachableIps(int currentIp, HashMap> refs, Set reachable, Set visited) { - do { - if (visited.contains(currentIp)) { - return false; - } - reachable.add(currentIp); - visited.add(currentIp); - if (refs.containsKey(currentIp)) { - List currentRefs = refs.get(currentIp); - if ((currentRefs != null) && (!currentRefs.isEmpty())) { - if (currentRefs.size() == 1) { - currentIp = currentRefs.get(0); - continue; - } - boolean r = false; - for (int i = 0; i < currentRefs.size(); i++) { - Set nr = new HashSet<>(); - boolean v = getPreviousReachableIps(currentRefs.get(i), refs, nr, visited); - if ((!v) || nr.contains(0)) { - reachable.addAll(nr); - } - r = r || v; - } - return r; - } - } - currentIp--; - } while (currentIp >= 0); - return true; - } - - @Override - public AVM2Code clone() { - try { - AVM2Code ret = (AVM2Code) super.clone(); - if (code != null) { - List codeCopy = new ArrayList<>(code.size()); - for (AVM2Instruction ins : code) { - codeCopy.add(ins.clone()); - } - ret.code = codeCopy; - } - - ret.killedRegs = new HashMap<>(); - return ret; - } catch (CloneNotSupportedException ex) { - throw new RuntimeException(); - } - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.abc.avm2; + +import com.jpexs.decompiler.flash.EndOfStreamException; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.ABCInputStream; +import com.jpexs.decompiler.flash.abc.CopyOutputStream; +import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorGetSet; +import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorJumps; +import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorRegistersOld; +import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorSimpleOld; +import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2ExecutionException; +import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2VerifyErrorException; +import com.jpexs.decompiler.flash.abc.avm2.graph.AVM2Graph; +import com.jpexs.decompiler.flash.abc.avm2.graph.AVM2GraphSource; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2InstructionFlag; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; +import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; +import com.jpexs.decompiler.flash.abc.avm2.instructions.UnknownInstruction; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Lf32Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Lf64Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Li16Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Li32Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Li8Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Sf32Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Sf64Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Si16Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Si32Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Si8Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Sxi16Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Sxi1Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.Sxi8Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DivideIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.ModuloIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NegateIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NegateIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NotIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitAndIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitNotIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitOrIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitXorIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.LShiftIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.RShiftIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.URShiftIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.EqualsIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterEqualsIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterThanIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessEqualsIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessThanIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.StrictEqualsIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructPropIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructSuperIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewActivationIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewArrayIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewCatchIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewClassIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewObjectIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugFileIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugLineIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallMethodIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallPropLexIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallPropVoidIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallPropertyIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallStaticIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallSuperIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallSuperVoidIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfEqIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfFalseIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfGeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfGtIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfLeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfLtIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfNGeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfNGtIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfNLeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfNLtIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfNeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfStrictEqIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfStrictNeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfTrueIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.LookupSwitchIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.DecLocalIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.DecLocalIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocal0Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocal1Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocal2Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocal3Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.KillIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocal0Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocal1Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocal2Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocal3Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.DeletePropertyIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.FindDefIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.FindPropertyIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.FindPropertyStrictIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetDescendantsIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetGlobalScopeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetGlobalSlotIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetLexIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetPropertyIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetScopeObjectIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetSlotIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetSuperIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.HasNext2Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.HasNextIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.InIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.InitPropertyIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.LabelIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NextNameIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NextValueIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NopIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetGlobalSlotIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetPropertyIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetSlotIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetSuperIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.AbsJumpIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.AddDIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.AddPIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.AllocIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.BkptIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.BkptLineIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CallInterfaceIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CallSuperIdIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CodeGenOpIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CoerceBIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CoerceDIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CoerceIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CoerceOIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.CoerceUIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.ConcatIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.ConvertF4Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.ConvertFIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.ConvertMIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.ConvertMPIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DecLocalPIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DecodeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DecrementPIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DelDescendantsIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DeletePropertyLateIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DividePIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DoubleToAtomIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.FindPropGlobalIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.GetOuterScopeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.IncLocalPIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.IncrementPIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.InvalidIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.Lf32x4Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.MarkIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.ModuloPIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.MultiplyPIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.NegatePIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.PrologueIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.PushConstantIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.PushDNanIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.PushDecimalIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.PushFloat4Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.PushFloatIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.SendEnterIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.SetPropertyLateIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.Sf32x4Ins; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.SubtractPIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.SweepIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.TimestampIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.UnPlusIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.VerifyOpIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.VerifyPassIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.WbIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopScopeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushDoubleIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushFalseIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNamespaceIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNanIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNullIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushScopeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushStringIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushTrueIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUIntIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushWithIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.SwapIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ApplyTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.AsTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.AsTypeLateIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceAIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceOrConvertTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceSIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertBIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertDIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertOIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertSIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertUIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.InstanceOfIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.IsTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.IsTypeLateIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.TypeOfIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.CheckFilterIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.DXNSIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.DXNSLateIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.EscXAttrIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.EscXElemIns; +import com.jpexs.decompiler.flash.abc.avm2.model.CoerceAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.ConvertAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.InitPropertyAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.NewFunctionAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.ReturnVoidAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.SetPropertyAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.SetSlotAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.SetTypeAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.WithAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.clauses.DeclarationAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForEachInAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForInAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.PropertyAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; +import com.jpexs.decompiler.flash.abc.types.ABCException; +import com.jpexs.decompiler.flash.abc.types.AssignedValue; +import com.jpexs.decompiler.flash.abc.types.ConvertData; +import com.jpexs.decompiler.flash.abc.types.MethodBody; +import com.jpexs.decompiler.flash.abc.types.MethodInfo; +import com.jpexs.decompiler.flash.abc.types.Multiname; +import com.jpexs.decompiler.flash.abc.types.ValueKind; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction; +import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; +import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; +import com.jpexs.decompiler.flash.abc.types.traits.Traits; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.dumpview.DumpInfo; +import com.jpexs.decompiler.flash.ecma.Undefined; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; +import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; +import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; +import com.jpexs.decompiler.graph.Block; +import com.jpexs.decompiler.graph.DottedChain; +import com.jpexs.decompiler.graph.GraphPart; +import com.jpexs.decompiler.graph.GraphSourceItem; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.ScopeStack; +import com.jpexs.decompiler.graph.SimpleValue; +import com.jpexs.decompiler.graph.TranslateStack; +import com.jpexs.decompiler.graph.TypeItem; +import com.jpexs.decompiler.graph.model.BinaryOpItem; +import com.jpexs.decompiler.graph.model.ExitItem; +import com.jpexs.decompiler.graph.model.IfItem; +import com.jpexs.decompiler.graph.model.ScriptEndItem; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.ReflectionTools; +import com.jpexs.helpers.stat.Statistics; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class AVM2Code implements Cloneable { + + private static final Logger logger = Logger.getLogger(AVM2Code.class.getName()); + + private static final boolean DEBUG_MODE = false; + + public static int toSourceLimit = -1; + + public List code; + + public static boolean DEBUG_REWRITE = false; + + public static final int OPT_U30 = 0x100; + + public static final int OPT_U8 = 0x200; + + public static final int OPT_S24 = 0x300; + + public static final int OPT_CASE_OFFSETS = 0x400; + + public static final int OPT_S8 = 0x500; + + public static final int OPT_S16 = 0x600; + + public static final int DAT_MULTINAME_INDEX = OPT_U30 + 0x01; + + public static final int DAT_ARG_COUNT = OPT_U30 + 0x02; + + public static final int DAT_METHOD_INDEX = OPT_U30 + 0x03; + + public static final int DAT_STRING_INDEX = OPT_U30 + 0x04; + + public static final int DAT_DEBUG_TYPE = OPT_U8 + 0x05; + + public static final int DAT_REGISTER_INDEX = OPT_U8 + 0x06; + + public static final int DAT_LINENUM = OPT_U30 + 0x07; + + public static final int DAT_LOCAL_REG_INDEX = OPT_U30 + 0x08; + + public static final int DAT_SLOT_INDEX = OPT_U30 + 0x09; + + public static final int DAT_SCOPE_INDEX = OPT_U30 + 0x0A; + + public static final int DAT_OFFSET = OPT_S24 + 0x0B; + + public static final int DAT_EXCEPTION_INDEX = OPT_U30 + 0x0C; + + public static final int DAT_CLASS_INDEX = OPT_U30 + 0x0D; + + public static final int DAT_INT_INDEX = OPT_U30 + 0x0E; + + public static final int DAT_UINT_INDEX = OPT_U30 + 0x0F; + + public static final int DAT_DOUBLE_INDEX = OPT_U30 + 0x10; + + public static final int DAT_DECIMAL_INDEX = OPT_U30 + 0x11; + + public static final int DAT_CASE_BASEOFFSET = OPT_S24 + 0x12; + + public static final int DAT_NUMBER_CONTEXT = OPT_U30 + 0x13; + + public static final int DAT_DISPATCH_ID = OPT_U30 + 0x14; + + public static final int DAT_FLOAT_INDEX = OPT_U30 + 0x15; + + public static final int DAT_FLOAT4_INDEX = OPT_U30 + 0x16; + + public static final int DAT_NAMESPACE_INDEX = OPT_U30 + 0x17; + + public static String operandTypeSizeToString(int ot) { + int sizeType = ot & 0xff00; + switch (sizeType) { + case OPT_U30: + return "U30"; + case OPT_S16: + return "S16"; + case OPT_U8: + return "U8"; + case OPT_S8: + return "S8"; + case OPT_S24: + return "S24"; + case OPT_CASE_OFFSETS: + return "S24(=n), S24[n]"; + } + return ""; + } + + private static Map operandDataTypeIdentifiers = ReflectionTools.getConstNamesMap(AVM2Code.class, Integer.class, "^DAT_(.*)$"); + + public static String operandTypeToString(int ot, boolean withTypeSize) { + String typeSize = operandTypeSizeToString(ot); + if (ot == OPT_CASE_OFFSETS) { + return "number" + (withTypeSize ? "(U30)" : "") + ", offset" + (withTypeSize ? "(S24)" : "") + ", offset" + (withTypeSize ? "(S24)" : "") + ", ..."; + } + if (operandDataTypeIdentifiers.containsKey(ot)) { + String dataType = operandDataTypeIdentifiers.get(ot); + return dataType + (withTypeSize ? "(" + typeSize + ")" : ""); + } else { + return typeSize; + } + + } + + public static final InstructionDefinition[] instructionSet = new InstructionDefinition[256]; + + public static final InstructionDefinition[] allInstructionSet = new InstructionDefinition[]{ + /*0x00*/null, + /*0x01*/ new BkptIns(), + /*0x02*/ new NopIns(), + /*0x03*/ new ThrowIns(), + /*0x04*/ new GetSuperIns(), + /*0x05*/ new SetSuperIns(), + /*0x06*/ new DXNSIns(), + /*0x07*/ new DXNSLateIns(), + /*0x08*/ new KillIns(), + /*0x09*/ new LabelIns(), + /*0x0A*/ new Lf32x4Ins(), + /*0x0B*/ new Sf32x4Ins(), + /*0x0C*/ new IfNLtIns(), + /*0x0D*/ new IfNLeIns(), + /*0x0E*/ new IfNGtIns(), + /*0x0F*/ new IfNGeIns(), + /*0x10*/ new JumpIns(), + /*0x11*/ new IfTrueIns(), + /*0x12*/ new IfFalseIns(), + /*0x13*/ new IfEqIns(), + /*0x14*/ new IfNeIns(), + /*0x15*/ new IfLtIns(), + /*0x16*/ new IfLeIns(), + /*0x17*/ new IfGtIns(), + /*0x18*/ new IfGeIns(), + /*0x19*/ new IfStrictEqIns(), + /*0x1A*/ new IfStrictNeIns(), + /*0x1B*/ new LookupSwitchIns(), + /*0x1C*/ new PushWithIns(), + /*0x1D*/ new PopScopeIns(), + /*0x1E*/ new NextNameIns(), + /*0x1F*/ new HasNextIns(), + /*0x20*/ new PushNullIns(), + /*0x21*/ new PushUndefinedIns(), + /*0x22*/ new PushFloatIns(), //major 47+ + /*0x22*/ new PushConstantIns(), //before major 47 + /*0x23*/ new NextValueIns(), + /*0x24*/ new PushByteIns(), + /*0x25*/ new PushShortIns(), + /*0x26*/ new PushTrueIns(), + /*0x27*/ new PushFalseIns(), + /*0x28*/ new PushNanIns(), + /*0x29*/ new PopIns(), + /*0x2A*/ new DupIns(), + /*0x2B*/ new SwapIns(), + /*0x2C*/ new PushStringIns(), + /*0x2D*/ new PushIntIns(), + /*0x2E*/ new PushUIntIns(), + /*0x2F*/ new PushDoubleIns(), + /*0x30*/ new PushScopeIns(), + /*0x31*/ new PushNamespaceIns(), + /*0x32*/ new HasNext2Ins(), + /*0x33*/ new PushDecimalIns(), //pushdecimal(minor 17), lix8 (internal-only) according to Tamarin + /*0x34*/ new PushDNanIns(), //pushdnan according to Flex SDK, lix16 (internal-only) according to Tamarin + /*0x35*/ new Li8Ins(), + /*0x36*/ new Li16Ins(), + /*0x37*/ new Li32Ins(), + /*0x38*/ new Lf32Ins(), + /*0x39*/ new Lf64Ins(), + /*0x3A*/ new Si8Ins(), + /*0x3B*/ new Si16Ins(), + /*0x3C*/ new Si32Ins(), + /*0x3D*/ new Sf32Ins(), + /*0x3E*/ new Sf64Ins(), + /*0x3F*/ null, + /*0x40*/ new NewFunctionIns(), + /*0x41*/ new CallIns(), + /*0x42*/ new ConstructIns(), + /*0x43*/ new CallMethodIns(), + /*0x44*/ new CallStaticIns(), + /*0x45*/ new CallSuperIns(), + /*0x46*/ new CallPropertyIns(), + /*0x47*/ new ReturnVoidIns(), + /*0x48*/ new ReturnValueIns(), + /*0x49*/ new ConstructSuperIns(), + /*0x4A*/ new ConstructPropIns(), + /*0x4B*/ new CallSuperIdIns(), + /*0x4C*/ new CallPropLexIns(), + /*0x4D*/ new CallInterfaceIns(), + /*0x4E*/ new CallSuperVoidIns(), + /*0x4F*/ new CallPropVoidIns(), + /*0x50*/ new Sxi1Ins(), + /*0x51*/ new Sxi8Ins(), + /*0x52*/ new Sxi16Ins(), + /*0x53*/ new ApplyTypeIns(), + /*0x54*/ new PushFloat4Ins(), //major 47+ + /*0x55*/ new NewObjectIns(), + /*0x56*/ new NewArrayIns(), + /*0x57*/ new NewActivationIns(), + /*0x58*/ new NewClassIns(), + /*0x59*/ new GetDescendantsIns(), + /*0x5A*/ new NewCatchIns(), + /*0x5B*/ new DelDescendantsIns(), //deldescendants according to Flex, findpropglobalstrict(internal-only) according to Tamarin + /*0x5C*/ new FindPropGlobalIns(), //Tamarin (internal-only) + /*0x5D*/ new FindPropertyStrictIns(), + /*0x5E*/ new FindPropertyIns(), + /*0x5F*/ new FindDefIns(), + /*0x60*/ new GetLexIns(), + /*0x61*/ new SetPropertyIns(), + /*0x62*/ new GetLocalIns(), + /*0x63*/ new SetLocalIns(), + /*0x64*/ new GetGlobalScopeIns(), + /*0x65*/ new GetScopeObjectIns(), + /*0x66*/ new GetPropertyIns(), + /*0x67*/ new GetOuterScopeIns(), // new GetPropertyLateIns() + /*0x68*/ new InitPropertyIns(), + /*0x69*/ new SetPropertyLateIns(), + /*0x6A*/ new DeletePropertyIns(), + /*0x6B*/ new DeletePropertyLateIns(), + /*0x6C*/ new GetSlotIns(), + /*0x6D*/ new SetSlotIns(), + /*0x6E*/ new GetGlobalSlotIns(), + /*0x6F*/ new SetGlobalSlotIns(), + /*0x70*/ new ConvertSIns(), + /*0x71*/ new EscXElemIns(), + /*0x72*/ new EscXAttrIns(), + /*0x73*/ new ConvertIIns(), + /*0x74*/ new ConvertUIns(), + /*0x75*/ new ConvertDIns(), + /*0x76*/ new ConvertBIns(), + /*0x77*/ new ConvertOIns(), + /*0x78*/ new CheckFilterIns(), + /*0x79*/ new ConvertMIns(), //minor 17 (Flex) + /*0x79*/ new ConvertFIns(), //major 47+, SWF 15+ + /*0x7A*/ new ConvertMPIns(), //minor 17 (Flex) + /*0x7A*/ new UnPlusIns(), //major 47+, SWF 15+ + /*0x7B*/ new ConvertF4Ins(), //major 47+, SWF 15+ + /*0x7C*/ null, + /*0x7D*/ null, + /*0x7E*/ null, + /*0x7F*/ null, + /*0x80*/ new CoerceIns(), + /*0x81*/ new CoerceBIns(), + /*0x82*/ new CoerceAIns(), + /*0x83*/ new CoerceIIns(), + /*0x84*/ new CoerceDIns(), + /*0x85*/ new CoerceSIns(), + /*0x86*/ new AsTypeIns(), + /*0x87*/ new AsTypeLateIns(), + /*0x88*/ new CoerceUIns(), + /*0x89*/ new CoerceOIns(), + /*0x8A*/ null, + /*0x8B*/ null, + /*0x8C*/ null, + /*0x8D*/ null, + /*0x8E*/ null, + /*0x8F*/ new NegatePIns(), + /*0x90*/ new NegateIns(), + /*0x91*/ new IncrementIns(), + /*0x92*/ new IncLocalIns(), + /*0x93*/ new DecrementIns(), + /*0x94*/ new DecLocalIns(), + /*0x95*/ new TypeOfIns(), + /*0x96*/ new NotIns(), + /*0x97*/ new BitNotIns(), + /*0x98*/ null, + /*0x99*/ null, + /*0x9A*/ new ConcatIns(), + /*0x9B*/ new AddDIns(), + /*0x9C*/ new IncrementPIns(), + /*0x9D*/ new IncLocalPIns(), + /*0x9E*/ new DecrementPIns(), + /*0x9F*/ new DecLocalPIns(), + /*0xA0*/ new AddIns(), + /*0xA1*/ new SubtractIns(), + /*0xA2*/ new MultiplyIns(), + /*0xA3*/ new DivideIns(), + /*0xA4*/ new ModuloIns(), + /*0xA5*/ new LShiftIns(), + /*0xA6*/ new RShiftIns(), + /*0xA7*/ new URShiftIns(), + /*0xA8*/ new BitAndIns(), + /*0xA9*/ new BitOrIns(), + /*0xAA*/ new BitXorIns(), + /*0xAB*/ new EqualsIns(), + /*0xAC*/ new StrictEqualsIns(), + /*0xAD*/ new LessThanIns(), + /*0xAE*/ new LessEqualsIns(), + /*0xAF*/ new GreaterThanIns(), + /*0xB0*/ new GreaterEqualsIns(), + /*0xB1*/ new InstanceOfIns(), + /*0xB2*/ new IsTypeIns(), + /*0xB3*/ new IsTypeLateIns(), + /*0xB4*/ new InIns(), + /*0xB5*/ new AddPIns(), + /*0xB6*/ new SubtractPIns(), + /*0xB7*/ new MultiplyPIns(), + /*0xB8*/ new DividePIns(), + /*0xB9*/ new ModuloPIns(), + /*0xBA*/ null, + /*0xBB*/ null, + /*0xBC*/ null, + /*0xBD*/ null, + /*0xBE*/ null, + /*0xBF*/ null, + /*0xC0*/ new IncrementIIns(), + /*0xC1*/ new DecrementIIns(), + /*0xC2*/ new IncLocalIIns(), + /*0xC3*/ new DecLocalIIns(), + /*0xC4*/ new NegateIIns(), + /*0xC5*/ new AddIIns(), + /*0xC6*/ new SubtractIIns(), + /*0xC7*/ new MultiplyIIns(), + /*0xC8*/ null, + /*0xC9*/ null, + /*0xCA*/ null, + /*0xCB*/ null, + /*0xCC*/ null, + /*0xCD*/ null, + /*0xCE*/ null, + /*0xCF*/ null, + /*0xD0*/ new GetLocal0Ins(), + /*0xD1*/ new GetLocal1Ins(), + /*0xD2*/ new GetLocal2Ins(), + /*0xD3*/ new GetLocal3Ins(), + /*0xD4*/ new SetLocal0Ins(), + /*0xD5*/ new SetLocal1Ins(), + /*0xD6*/ new SetLocal2Ins(), + /*0xD7*/ new SetLocal3Ins(), + /*0xD8*/ null, + /*0xD9*/ null, + /*0xDA*/ null, + /*0xDB*/ null, + /*0xDC*/ null, + /*0xDD*/ null, + /*0xDE*/ null, + /*0xDF*/ null, + /*0xE0*/ null, + /*0xE1*/ null, + /*0xE2*/ null, + /*0xE3*/ null, + /*0xE4*/ null, + /*0xE5*/ null, + /*0xE6*/ null, + /*0xE7*/ null, + /*0xE8*/ null, + /*0xE9*/ null, + /*0xEA*/ null, + /*0xEB*/ null, + /*0xEC*/ null, + /*0xED*/ new InvalidIns(), + /*0xEE*/ new AbsJumpIns(), + /*0xEF*/ new DebugIns(), + /*0xF0*/ new DebugLineIns(), + /*0xF1*/ new DebugFileIns(), + /*0xF2*/ new BkptLineIns(), + /*0xF3*/ new TimestampIns(), + /*0xF4*/ null, + /*0xF5*/ new VerifyPassIns(), + /*0xF6*/ new AllocIns(), + /*0xF7*/ new MarkIns(), + /*0xF8*/ new WbIns(), + /*0xF9*/ new PrologueIns(), + /*0xFA*/ new SendEnterIns(), + /*0xFB*/ new DoubleToAtomIns(), + /*0xFC*/ new SweepIns(), + /*0xFD*/ new CodeGenOpIns(), + /*0xFE*/ new VerifyOpIns(), + /*0xFF*/ new DecodeIns(),}; + // endoflist + + static { + + for (int i = 0; i < allInstructionSet.length; i++) { + if (allInstructionSet[i] != null) { + int opCode = allInstructionSet[i].instructionCode; + if (instructionSet[opCode] == null) { + instructionSet[opCode] = allInstructionSet[i]; + } else if (instructionSet[opCode].hasFlag(AVM2InstructionFlag.NO_FLASH_PLAYER) && !allInstructionSet[i].hasFlag(AVM2InstructionFlag.NO_FLASH_PLAYER)) { + instructionSet[opCode] = allInstructionSet[i]; + } //Prefer without decimal: + else if (instructionSet[opCode].hasFlag(AVM2InstructionFlag.ES4_NUMERICS_MINOR) && !allInstructionSet[i].hasFlag(AVM2InstructionFlag.ES4_NUMERICS_MINOR)) { + instructionSet[opCode] = allInstructionSet[i]; + } //Prefer without float: + else if (instructionSet[opCode].hasFlag(AVM2InstructionFlag.FLOAT_MAJOR) && !allInstructionSet[i].hasFlag(AVM2InstructionFlag.FLOAT_MAJOR)) { + instructionSet[opCode] = allInstructionSet[i]; + } + } + } + + for (int i = 0; + i < instructionSet.length; + i++) { + if (instructionSet[i] == null) { + instructionSet[i] = new UnknownInstruction(i); + } + } + + } + + public static final String IDENTOPEN = "/*IDENTOPEN*/"; + + public static final String IDENTCLOSE = "/*IDENTCLOSE*/"; + + public AVM2Code() { + code = new ArrayList<>(); + } + + public AVM2Code(int capacity) { + code = new ArrayList<>(capacity); + } + + public AVM2Code(ArrayList instructions) { + code = instructions; + } + + public Object execute(HashMap arguments, AVM2ConstantPool constants) throws AVM2ExecutionException { + return execute(arguments, constants, null); + } + + public Object execute(HashMap arguments, AVM2ConstantPool constants, AVM2RuntimeInfo runtimeInfo) throws AVM2ExecutionException { + int pos = 0; + LocalDataArea lda = new LocalDataArea(); + lda.methodName = "methodName"; // todo: needed for VerifyError exception message + lda.localRegisters = arguments; + lda.runtimeInfo = runtimeInfo; + + for (AVM2Instruction ins : code) { + ins.definition.verify(lda, constants, ins); + } + + while (pos < code.size()) { + AVM2Instruction ins = code.get(pos); + if (!ins.definition.execute(lda, constants, ins)) { + return null; + } + + if (lda.jump != null) { + try { + pos = adr2pos(lda.jump); + } catch (ConvertException ex) { + throw new AVM2VerifyErrorException(AVM2VerifyErrorException.BRANCH_TARGET_INVALID_INSTRUCTION, lda.isDebug()); + } + lda.jump = null; + } else { + pos++; + } + + if (lda.returnValue != null) { + return lda.returnValue; + } + } + + return Undefined.INSTANCE; + } + + public void calculateDebugFileLine(ABC abc) { + calculateDebugFileLine(null, 0, 0, abc, new HashSet<>()); + } + + private boolean calculateDebugFileLine(String debugFile, int debugLine, int pos, ABC abc, Set seen) { + while (pos < code.size()) { + AVM2Instruction ins = code.get(pos); + if (seen.contains(pos)) { + return true; + } + + seen.add(pos); + + if (ins.definition instanceof DebugFileIns) { + debugFile = abc.constants.getString(ins.operands[0]); + } + + if (ins.definition instanceof DebugLineIns) { + debugLine = ins.operands[0]; + } + + ins.setFileLine(debugFile, debugLine); + + if (ins.definition instanceof NewFunctionIns) { + //Only analyze NewFunction objects that are not immediately discarded by Pop. + //This avoids bogus functions used in obfuscation or special compilers that can lead to infinite recursion. + if ((pos + 1 < code.size()) && !(code.get(pos + 1).definition instanceof PopIns)) { + MethodBody innerBody = abc.findBody(ins.operands[0]); + if (innerBody != null) { //Ignore functions without body + innerBody.getCode().calculateDebugFileLine(debugFile, debugLine, 0, abc, new HashSet<>()); + } + } + } + + if (ins.definition instanceof ReturnValueIns) { + return true; + } + if (ins.definition instanceof ReturnVoidIns) { + return true; + } + if (ins.definition instanceof JumpIns) { + try { + pos = adr2pos(ins.getTargetAddress()); + continue; + } catch (ConvertException ex) { + return false; + } + } else if (ins.definition instanceof IfTypeIns) { + try { + int newpos = adr2pos(ins.getTargetAddress()); + calculateDebugFileLine(debugFile, debugLine, newpos, abc, seen); + } catch (ConvertException ex) { + return false; + } + } + if (ins.definition instanceof LookupSwitchIns) { + for (int i = 0; i < ins.operands.length; i++) { + if (i == 1) { + continue; + } + try { + int newpos = adr2pos(pos2adr(pos) + ins.operands[i]); + if (!calculateDebugFileLine(debugFile, debugLine, newpos, abc, seen)) { + return false; + } + } catch (ConvertException ex) { + return false; + } + } + } + pos++; + } + return true; + } + + /** + * Removes nonexistent indices to constants from instruction operands. + * + * @param constants + */ + public void removeWrongIndices(AVM2ConstantPool constants) { + for (AVM2Instruction ins : code) { + for (int i = 0; i < ins.definition.operands.length; i++) { + if (ins.definition.operands[i] == DAT_MULTINAME_INDEX && ins.operands[i] >= constants.getMultinameCount()) { + ins.operands[i] = 0; + } + if (ins.definition.operands[i] == DAT_DOUBLE_INDEX && ins.operands[i] >= constants.getDoubleCount()) { + ins.operands[i] = 0; + } + if (ins.definition.operands[i] == DAT_INT_INDEX && ins.operands[i] >= constants.getIntCount()) { + ins.operands[i] = 0; + } + if (ins.definition.operands[i] == DAT_UINT_INDEX && ins.operands[i] >= constants.getUIntCount()) { + ins.operands[i] = 0; + } + if (ins.definition.operands[i] == DAT_STRING_INDEX && ins.operands[i] >= constants.getStringCount()) { + ins.operands[i] = 0; + } + } + } + } + + public AVM2Code(ABCInputStream ais, MethodBody body) throws IOException { + Map codeMap = new HashMap<>(); + DumpInfo diParent = ais.dumpInfo; + List addresses = new ArrayList<>(); + //Do not add new jumps when processing these addresses (unreachable code,etc.) + List unAdresses = new ArrayList<>(); + //Handle lookupswitches at the end - they can be invalid. Handle other instruction first so we can decide lookupswitch to be invalid based on other instructions inside it + //Flashplayer does not check casecount in lookupswitch instruction so the instruction can "be" long and over other instructions + List switchAddresses = new ArrayList<>(); + int availableBytes = ais.available(); + for (int i = 0; i < availableBytes; i++) { + codeMap.put((long) i, new AVM2Instruction(i, AVM2Instructions.Nop, null)); + } + + long startPos = ais.getPosition(); + addresses.add(startPos); + if (body != null) { + for (ABCException e : body.exceptions) { + addresses.add((long) e.start); + addresses.add((long) e.end); + addresses.add((long) e.target); + } + } + + loopaddr: + while (!addresses.isEmpty() || !switchAddresses.isEmpty() || !unAdresses.isEmpty()) { + long address; + boolean isSwitch = false; + boolean handleJumps = true; + if (!addresses.isEmpty()) { + address = addresses.remove(0); + } else if (!switchAddresses.isEmpty()) { + address = switchAddresses.remove(0); + isSwitch = true; + } else { + address = unAdresses.remove(0); + handleJumps = false; + } + if (address < startPos) // no jump outside block + { + continue; + } + try { + ais.seek(address); + while (ais.available() > 0) { + long startOffset = ais.getPosition(); + + if (codeMap.containsKey(startOffset) && !(codeMap.get(startOffset).definition instanceof NopIns)) { + continue loopaddr; + } + + DumpInfo di = ais.newDumpLevel("instruction", "instruction"); + InstructionDefinition instr = null; + try { + int instructionCode = ais.read("instructionCode"); + instr = instructionSet[instructionCode]; + if (instructionCode == AVM2Instructions.LookupSwitch) { + if (!isSwitch) { + switchAddresses.add(startOffset); + continue loopaddr; + } else { + isSwitch = false; + } + } + if (di != null) { + di.name = instr.instructionName; + } + if (instr != null) { + int[] actualOperands = null; + + if (instructionCode == AVM2Instructions.LookupSwitch) { // switch + int firstOperand = ais.readS24("default_offset"); + int case_count = ais.readU30("case_count"); + long afterCasePos = ais.getPosition() + 3 * (case_count + 1); + + boolean invalidSwitch = false; + //If there are already some instructions in the lookupswitch bytes, the lookupswitch is invalid (obfuscation) + for (long a = startOffset; a < afterCasePos; a++) { + if (codeMap.containsKey(a) && (!(codeMap.get(a).definition instanceof NopIns))) { + invalidSwitch = true; + break; + } + } + + long totalBytes = ais.getPosition() + ais.available(); + + //If the lookupswitch case_count are larger than available bytes, the lookupswitch is invalid (obfuscation) + if (afterCasePos > totalBytes) { + invalidSwitch = true; + } + if (invalidSwitch) { + continue loopaddr; + } else { + actualOperands = new int[case_count + 3]; + actualOperands[0] = firstOperand; + actualOperands[1] = case_count; + for (int c = 0; c < case_count + 1; c++) { + actualOperands[2 + c] = ais.readS24("actualOperand"); + } + } + } else if (instr.operands.length > 0) { + actualOperands = new int[instr.operands.length]; + for (int op = 0; op < instr.operands.length; op++) { + switch (instr.operands[op] & 0xff00) { + case OPT_U30: + actualOperands[op] = ais.readU30("operand"); + break; + case OPT_S16: + actualOperands[op] = (short) ais.readU30("operand"); + break; + case OPT_U8: + actualOperands[op] = ais.read("operand"); + break; + case OPT_S8: + actualOperands[op] = (byte) ais.read("operand"); + break; + case OPT_S24: + actualOperands[op] = ais.readS24("operand"); + break; + } + } + } + + AVM2Instruction ai = new AVM2Instruction(startOffset, instr, actualOperands); + long endOffset = ais.getPosition(); + + boolean hasRoom = true; + for (long p = startOffset; p < endOffset; p++) { + if (codeMap.containsKey(p) && !(codeMap.get(p).definition instanceof NopIns)) { + hasRoom = false; + } + } + + //There is no room for this instruction (it is invalid?) + if (!hasRoom) { + continue loopaddr; + } + for (long p = startOffset; p < endOffset; p++) { + codeMap.put(p, ai); + } + + if ((instr instanceof IfTypeIns)) { + if (handleJumps) { + long target = ais.getPosition() + actualOperands[0]; + addresses.add(target); + } else { + actualOperands[0] = 0; + } + } + + if (instr instanceof JumpIns) { + if (handleJumps) { + long target = ais.getPosition() + actualOperands[0]; + addresses.add(target); + unAdresses.add(ais.getPosition()); + continue loopaddr; + } else { + actualOperands[0] = 0; + } + } + + if (instr.isExitInstruction()) { //do not process jumps if there is return/throw instruction + if (handleJumps) { + unAdresses.add(ais.getPosition()); + continue loopaddr; + } + } + if ((instr instanceof LookupSwitchIns) && actualOperands != null) { + if (handleJumps) { + addresses.add(startOffset + actualOperands[0]); + + for (int c = 2; c < actualOperands.length; c++) { + addresses.add(startOffset + actualOperands[c]); + } + unAdresses.add(ais.getPosition()); + continue loopaddr; + } else { + int swlen = (int) (endOffset - startOffset); + actualOperands[0] = swlen; + for (int c = 2; c < actualOperands.length; c++) { + actualOperands[c] = swlen; + } + } + } + + } else { + break; // Unknown instructions are ignored (Some of the obfuscators add unknown instructions) + //throw new UnknownInstructionCode(instructionCode); + } + } finally { + if (instr == null) { + ais.endDumpLevel(); + } else { + ais.endDumpLevel(instr.instructionCode); + } + } + } + } catch (EndOfStreamException ex) { + // lookupswitch obfuscation, ignore + ais.endDumpLevelUntil(diParent); + } + } + + if (diParent != null) { + diParent.sortChildren(); + } + + code = new ArrayList<>(codeMap.size()); + AVM2Instruction prev = null; + for (int i = 0; i < availableBytes; i++) { + AVM2Instruction ins = codeMap.get((long) i); + if (prev != ins) { + code.add(ins); + } + prev = ins; + } + } + + public void compact() { + if (code instanceof ArrayList) { + ((ArrayList) code).trimToSize(); + } + } + + public byte[] getBytes() { + return getBytes(null); + } + + public byte[] getBytes(byte[] origBytes) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + OutputStream cos; + if ((origBytes != null) && (DEBUG_REWRITE)) { + ByteArrayInputStream origis = new ByteArrayInputStream(origBytes); + cos = new CopyOutputStream(bos, origis); + } else { + cos = bos; + } + try { + for (AVM2Instruction instruction : code) { + cos.write(instruction.getBytes()); + } + } catch (IOException ex) { + } + return bos.toByteArray(); + } + + public void markOffsets() { + long address = 0; + for (int i = 0; i < code.size(); i++) { + code.get(i).setAddress(address); + address += code.get(i).getBytesLength(); + } + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + for (AVM2Instruction instruction : code) { + s.append(instruction.toString()); + s.append(Helper.newLine); + } + return s.toString(); + } + + public String toASMSource() { + return toASMSource(new AVM2ConstantPool()); + } + + public String toASMSource(AVM2ConstantPool constants) { + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); + toASMSource(constants, null, null, null, new ArrayList<>(), ScriptExportMode.PCODE, writer); + return writer.toString(); + } + + public GraphTextWriter toASMSource(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body, ScriptExportMode exportMode, GraphTextWriter writer) { + return toASMSource(constants, trait, info, body, new ArrayList<>(), exportMode, writer); + } + + public GraphTextWriter toASMSource(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body, List outputMap, ScriptExportMode exportMode, GraphTextWriter writer) { + if (trait != null) { + if (trait instanceof TraitFunction) { + TraitFunction tf = (TraitFunction) trait; + writer.appendNoHilight("trait "); + writer.hilightSpecial("function ", HighlightSpecialType.TRAIT_TYPE); + writer.hilightSpecial(constants.multinameToString(tf.name_index), HighlightSpecialType.TRAIT_NAME); + writer.appendNoHilight(" slotid "); + writer.hilightSpecial("" + tf.slot_id, HighlightSpecialType.SLOT_ID); + writer.newLine(); + } + if (trait instanceof TraitMethodGetterSetter) { + TraitMethodGetterSetter tm = (TraitMethodGetterSetter) trait; + writer.appendNoHilight("trait "); + switch (tm.kindType) { + case Trait.TRAIT_METHOD: + writer.hilightSpecial("method ", HighlightSpecialType.TRAIT_TYPE); + break; + case Trait.TRAIT_GETTER: + writer.hilightSpecial("getter ", HighlightSpecialType.TRAIT_TYPE); + break; + case Trait.TRAIT_SETTER: + writer.hilightSpecial("setter ", HighlightSpecialType.TRAIT_TYPE); + break; + } + writer.hilightSpecial(constants.multinameToString(tm.name_index), HighlightSpecialType.TRAIT_NAME); + writer.appendNoHilight(" dispid "); + writer.hilightSpecial("" + tm.disp_id, HighlightSpecialType.DISP_ID); + writer.newLine(); + } + } + + if (info != null) { + writer.appendNoHilight("method").newLine(); + writer.appendNoHilight("name "); + writer.hilightSpecial(info.name_index == 0 ? "null" : "\"" + Helper.escapeActionScriptString(info.getName(constants)) + "\"", HighlightSpecialType.METHOD_NAME); + writer.newLine(); + if (info.flagExplicit()) { + writer.appendNoHilight("flag "); + writer.hilightSpecial("EXPLICIT", HighlightSpecialType.FLAG_EXPLICIT); + writer.newLine(); + } + if (info.flagHas_optional()) { + writer.appendNoHilight("flag "); + writer.hilightSpecial("HAS_OPTIONAL", HighlightSpecialType.FLAG_HAS_OPTIONAL); + writer.newLine(); + writer.appendNoHilight("flag HAS_OPTIONAL").newLine(); + } + if (info.flagHas_paramnames()) { + writer.appendNoHilight("flag "); + writer.hilightSpecial("HAS_PARAM_NAMES", HighlightSpecialType.FLAG_HAS_PARAM_NAMES); + writer.newLine(); + } + if (info.flagIgnore_rest()) { + writer.appendNoHilight("flag "); + writer.hilightSpecial("EXPLICIT", HighlightSpecialType.FLAG_IGNORE_REST); + writer.newLine(); + } + if (info.flagNeed_activation()) { + writer.appendNoHilight("flag "); + writer.hilightSpecial("NEED_ACTIVATION", HighlightSpecialType.FLAG_NEED_ACTIVATION); + writer.newLine(); + } + if (info.flagNeed_arguments()) { + writer.appendNoHilight("flag "); + writer.hilightSpecial("NEED_ARGUMENTS", HighlightSpecialType.FLAG_NEED_ARGUMENTS); + writer.newLine(); + } + if (info.flagNeed_rest()) { + writer.appendNoHilight("flag "); + writer.hilightSpecial("NEED_REST", HighlightSpecialType.FLAG_NEED_REST); + writer.newLine(); + } + if (info.flagSetsdxns()) { + writer.appendNoHilight("flag "); + writer.hilightSpecial("SET_DXNS", HighlightSpecialType.FLAG_SET_DXNS); + writer.newLine(); + } + for (int p = 0; p < info.param_types.length; p++) { + writer.appendNoHilight("param "); + writer.hilightSpecial(constants.multinameToString(info.param_types[p]), HighlightSpecialType.PARAM, p); + writer.newLine(); + } + if (info.flagHas_paramnames()) { + for (int n : info.paramNames) { + writer.appendNoHilight("paramname "); + if (n == 0) { + writer.appendNoHilight("null"); + } else { + writer.appendNoHilight("\""); + writer.appendNoHilight(constants.getString(n)); + writer.appendNoHilight("\""); + } + writer.newLine(); + } + } + if (info.flagHas_optional()) { + for (int i = 0; i < info.optional.length; i++) { + ValueKind vk = info.optional[i]; + writer.appendNoHilight("optional "); + writer.hilightSpecial(vk.toString(constants), HighlightSpecialType.OPTIONAL, i); + writer.newLine(); + } + } + writer.appendNoHilight("returns "); + writer.hilightSpecial(constants.multinameToString(info.ret_type), HighlightSpecialType.RETURNS); + writer.newLine(); + } + writer.newLine(); + + Set importantOffsets = getImportantOffsets(body, true); + if (body != null) { + writer.appendNoHilight("body").newLine(); + + writer.appendNoHilight("maxstack "); + writer.appendNoHilight(body.max_stack); + writer.newLine(); + + writer.appendNoHilight("localcount "); + writer.appendNoHilight(body.max_regs); + writer.newLine(); + + writer.appendNoHilight("initscopedepth "); + writer.appendNoHilight(body.init_scope_depth); + writer.newLine(); + + writer.appendNoHilight("maxscopedepth "); + writer.appendNoHilight(body.max_scope_depth); + writer.newLine(); + + for (int e = 0; e < body.exceptions.length; e++) { + ABCException exception = body.exceptions[e]; + writer.appendNoHilight("try"); + + writer.appendNoHilight(" from "); + writer.appendNoHilight("ofs"); + writer.appendNoHilight(Helper.formatAddress(exception.start)); + + writer.appendNoHilight(" to "); + writer.appendNoHilight("ofs"); + writer.appendNoHilight(Helper.formatAddress(exception.end)); + + writer.appendNoHilight(" target "); + writer.appendNoHilight("ofs"); + writer.appendNoHilight(Helper.formatAddress(exception.target)); + + writer.appendNoHilight(" type "); + writer.hilightSpecial(exception.type_index == 0 ? "null" : constants.getMultiname(exception.type_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_TYPE, e); + + writer.appendNoHilight(" name "); + writer.hilightSpecial(exception.name_index == 0 ? "null" : constants.getMultiname(exception.name_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_NAME, e); + writer.newLine(); + } + } + + writer.newLine(); + writer.appendNoHilight("code").newLine(); + + int ip = 0; + int largeLimit = 20000; + boolean markOffsets = code.size() <= largeLimit; + + if (exportMode == ScriptExportMode.HEX) { + Helper.byteArrayToHexWithHeader(writer, getBytes()); + } else if (exportMode == ScriptExportMode.PCODE || exportMode == ScriptExportMode.PCODE_HEX) { + for (AVM2Instruction ins : code) { + long addr = ins.getAddress(); + if (exportMode == ScriptExportMode.PCODE_HEX) { + writer.appendNoHilight("; "); + writer.appendNoHilight(Helper.bytesToHexString(ins.getBytes())); + writer.newLine(); + } + if (Configuration.showAllAddresses.get() || importantOffsets.contains(addr)) { + writer.appendNoHilight("ofs" + Helper.formatAddress(addr) + ":"); + } + /*for (int e = 0; e < body.exceptions.length; e++) { + if (body.exceptions[e].start == ofs) { + ret.append("exceptionstart " + e + ":"); + } + if (body.exceptions[e].end == ofs) { + ret.append("exceptionend " + e + ":"); + } + if (body.exceptions[e].target == ofs) { + ret.append("exceptiontarget " + e + ":"); + } + }*/ + + if (!ins.isIgnored()) { + if (markOffsets) { + writer.append("", addr, ins.getFileOffset()); + } + + writer.appendNoHilight(ins.toStringNoAddress(constants, new ArrayList<>())); + writer.newLine(); + outputMap.add(ip); + } + + ip++; + } + } else if (exportMode == ScriptExportMode.CONSTANTS) { + writer.appendNoHilight("Constant export mode is not supported.").newLine(); + } + + return writer; + } + + public Set getImportantOffsets(MethodBody body, boolean tryEnds) { + Set ret = new HashSet<>(); + if (body != null) { + for (ABCException exception : body.exceptions) { + ret.add((long) exception.start); + if (tryEnds) { + ret.add((long) exception.end); + } + ret.add((long) exception.target); + } + } + + for (AVM2Instruction ins : code) { + ret.addAll(ins.getOffsets()); + } + + return ret; + } + + public AVM2Instruction adr2ins(long address) throws ConvertException { + int pos = adr2pos(address, false); + if (pos == code.size()) { + // end + return null; + } + + return code.get(pos); + } + + public int adr2pos(long address) throws ConvertException { + return adr2pos(address, false); + } + + public int adr2pos(long address, boolean nearest) throws ConvertException { + int ret = adr2posNoEx(address); + if (ret < 0) { + if (nearest && address < getEndOffset()) { + return -ret - 1; + } + throw new ConvertException("Invalid jump to ofs" + Helper.formatAddress(address), -1); + } + return ret; + } + + private int adr2posNoEx(long address) { + int min = 0; + int max = code.size() - 1; + + while (max >= min) { + int mid = (min + max) / 2; + long midValue = code.get(mid).getAddress(); + if (midValue == address) { + return mid; + } else if (midValue < address) { + min = mid + 1; + } else { + max = mid - 1; + } + } + + if (address == getEndOffset()) { + return code.size(); + } + + return -min - 1; + } + + public long pos2adr(int pos) { + if (pos == code.size()) { + return getEndOffset(); + } + return (int) code.get(pos).getAddress(); + } + + public long getEndOffset() { + if (code.isEmpty()) { + return 0; + } + + AVM2Instruction ins = code.get(code.size() - 1); + return (int) (ins.getAddress() + ins.getBytesLength()); + } + + /** + * Test for killed register. CalcKilledStats must be called before + * + * @param regName + * @param start + * @param end + * @return + */ + public boolean isKilled(int regName, int start, int end) { + if (!killedRegs.containsKey(regName)) { + return false; + } + for (int ip : killedRegs.get(regName)) { + if (ip >= start && ip <= end) { + return true; + } + } + return false; + } + + private int toSourceCount = 0; + + public Map getLocalRegNamesFromDebug(ABC abc) { + Map localRegNames = new HashMap<>(); + + for (AVM2Instruction ins : code) { + if (ins.definition instanceof DebugIns) { + if (ins.operands[0] == 1) { + String v = abc.constants.getString(ins.operands[1]); + // Same name already exists, it may be wrong names inserted by obfuscator + if (localRegNames.values().contains(v)) { + return new HashMap<>(); + } + localRegNames.put(ins.operands[2] + 1, v); + } + } + } + + // TODO: Make this immune to using existing multinames (?) + return localRegNames; + } + + private Map> killedRegs = new HashMap<>(); + + public void calcKilledStats(MethodBody body) throws InterruptedException { + killedRegs.clear(); + HashMap> vis = visitCode(body); + + for (int k = 0; k < code.size(); k++) { + if (vis.get(k).isEmpty()) { + continue; + } + if (code.get(k).definition instanceof KillIns) { + int regid = code.get(k).operands[0]; + if (!killedRegs.containsKey(regid)) { + killedRegs.put(regid, new HashSet<>()); + } + killedRegs.get(regid).add(k); + } + } + } + + public List clearTemporaryRegisters(List input) { + List output = new ArrayList<>(input); + for (int i = 0; i < output.size(); i++) { + if (output.get(i) instanceof SetLocalAVM2Item) { + if (isKilled(((SetLocalAVM2Item) output.get(i)).regIndex, 0, code.size() - 1)) { + SetLocalAVM2Item lsi = (SetLocalAVM2Item) output.get(i); + if (i + 1 < output.size()) { + if (output.get(i + 1) instanceof ExitItem) { + GraphTargetItem rv = output.get(i + 1); + if (rv.value instanceof LocalRegAVM2Item) { + LocalRegAVM2Item lr = (LocalRegAVM2Item) rv.value; + if (lr.regIndex == lsi.regIndex) { + rv.value = lsi.value; + } + } + } + } + output.remove(i); + i--; + } + } else if (output.get(i) instanceof WithAVM2Item) { + clearTemporaryRegisters(((WithAVM2Item) output.get(i)).items); + } + } + return output; + } + + public int fixIPAfterDebugLine(int ip) { + if (code.isEmpty()) { + return ip; + } + if (ip >= code.size()) { + return code.size() - 1; + } + while (code.get(ip).definition instanceof DebugLineIns) { + ip++; + } + return ip; + } + + public long fixAddrAfterDebugLine(long addr) throws ConvertException { + return pos2adr(fixIPAfterDebugLine(adr2pos(addr, true))); + } + + public ConvertOutput toSourceOutput(boolean thisHasDefaultToPrimitive, Reference lineStartItem, String path, GraphPart part, boolean processJumps, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, TranslateStack stack, ScopeStack scopeStack, ABC abc, MethodBody body, int start, int end, HashMap localRegNames, List fullyQualifiedNames, boolean[] visited, HashMap localRegAssigmentIps, HashMap> refs) throws ConvertException, InterruptedException { + calcKilledStats(body); + boolean debugMode = DEBUG_MODE; + if (debugMode) { + System.err.println("OPEN SubSource:" + start + "-" + end + " " + code.get(start).toString() + " to " + code.get(end).toString()); + } + if (visited == null) { + visited = new boolean[code.size()]; + } + //if(true) return ""; + toSourceCount++; + if (toSourceLimit > 0 && toSourceCount >= toSourceLimit) { + throw new ConvertException("Limit of subs(" + toSourceLimit + ") was reached", start); + } + List output = new ArrayList<>(); + int ip = start; + //try { + //int addr; + iploop: + while (ip <= end) { + + boolean processTry = processJumps; + //addr = pos2adr(ip); + //int ipfix = fixIPAfterDebugLine(ip); + //int addrfix = pos2adr(ipfix); + //int maxend = -1; + + if (ip > end) { + break; + } + + if (visited[ip]) { + //logger.warning(path + ": Code already visited, ofs:" + Helper.formatAddress(pos2adr(ip)) + ", ip:" + ip); + break; + } + + if (Configuration.simplifyExpressions.get()) { + stack.simplify(); + } + visited[ip] = true; + AVM2Instruction ins = code.get(ip); + if (stack.isEmpty()) { + lineStartItem.setVal(ins); + } + + if (debugMode) { + System.err.println("translating ip " + ip + " ins " + ins.toString() + " stack:" + stack.toString() + " scopeStack:" + scopeStack.toString()); + } + if (ins.definition instanceof NewFunctionIns) { + if (ip + 1 <= end) { + if (code.get(ip + 1).definition instanceof PopIns) { + ip += 2; + continue; + } + } + } + /*if ((ip + 8 < code.size())) { //return in finally clause + if (ins.definition instanceof SetLocalTypeIns) { + if (code.get(ip + 1).definition instanceof PushByteIns) { + AVM2Instruction jmp = code.get(ip + 2); + if (jmp.definition instanceof JumpIns) { + if (jmp.operands[0] == 0) { + if (code.get(ip + 3).definition instanceof LabelIns) { + if (code.get(ip + 4).definition instanceof PopIns) { + if (code.get(ip + 5).definition instanceof LabelIns) { + AVM2Instruction gl = code.get(ip + 6); + if (gl.definition instanceof GetLocalTypeIns) { + if (((GetLocalTypeIns) gl.definition).getRegisterId(gl) == ((SetLocalTypeIns) ins.definition).getRegisterId(ins)) { + AVM2Instruction ki = code.get(ip + 7); + if (ki.definition instanceof KillIns) { + if (ki.operands[0] == ((SetLocalTypeIns) ins.definition).getRegisterId(ins)) { + if (code.get(ip + 8).definition instanceof ReturnValueIns) { + ip = ip + 8; + continue; + } + } + } + } + } + } + } + } + } + } + } + } + }//*/ + + /*if ((ip + 2 < code.size()) && (ins.definition instanceof NewCatchIns)) { // Filling local register in catch clause + if (code.get(ip + 1).definition instanceof DupIns) { + if (code.get(ip + 2).definition instanceof SetLocalTypeIns) { + ins.definition.translate(isStatic, classIndex, localRegs, stack, scopeStack, constants, ins, method_info, output, body, abc, localRegNames, fullyQualifiedNames); + ip += 3; + continue; + } + } + }*/ + if ((ins.definition instanceof GetLocalTypeIns) && (!output.isEmpty()) && (output.get(output.size() - 1) instanceof SetLocalAVM2Item) && (((SetLocalAVM2Item) output.get(output.size() - 1)).regIndex == ((GetLocalTypeIns) ins.definition).getRegisterId(ins)) && isKilled(((SetLocalAVM2Item) output.get(output.size() - 1)).regIndex, start, end)) { + SetLocalAVM2Item slt = (SetLocalAVM2Item) output.remove(output.size() - 1); + stack.push(slt.getValue()); + ip++; + } else if ((ins.definition instanceof SetLocalTypeIns) && (ip + 1 <= end) && (isKilled(((SetLocalTypeIns) ins.definition).getRegisterId(ins), ip, end))) { // set_local_x,get_local_x..kill x + AVM2Instruction insAfter = code.get(ip + 1); + if ((insAfter.definition instanceof GetLocalTypeIns) && (((GetLocalTypeIns) insAfter.definition).getRegisterId(insAfter) == ((SetLocalTypeIns) ins.definition).getRegisterId(ins))) { + GraphTargetItem before = stack.peek(); + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); + stack.push(before); + ip += 2; + continue iploop; + } else { + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); + ip++; + continue iploop; + } + } else if (ins.definition instanceof DupIns) { + int nextPos; + do { + AVM2Instruction insAfter = ip + 1 < code.size() ? code.get(ip + 1) : null; + if (insAfter == null) { + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); + ip++; + break; + } + AVM2Instruction insBefore = ins; + if (ip - 1 >= start) { + insBefore = code.get(ip - 1); + } + if (insAfter.definition instanceof ConvertBIns) { // SWF compiled with debug contain convert_b + ip++; + //addr = pos2adr(ip); + insAfter = code.get(ip + 1); + } + + boolean isAnd; + if (processJumps && (insAfter.definition instanceof IfFalseIns)) { + //stack.add("(" + stack.pop() + ")&&"); + isAnd = true; + } else if (processJumps && (insAfter.definition instanceof IfTrueIns)) { + //stack.add("(" + stack.pop() + ")||"); + isAnd = false; + } else if (insAfter.definition instanceof SetLocalTypeIns) { + // chained assignments + int reg = (((SetLocalTypeIns) insAfter.definition).getRegisterId(insAfter)); + for (int t = ip + 1; t <= end - 1; t++) { + if (code.get(t).definition instanceof KillIns) { + if (code.get(t).operands[0] == reg) { + break; + } + } + if (code.get(t).definition instanceof GetLocalTypeIns) { + if (((GetLocalTypeIns) code.get(t).definition).getRegisterId(code.get(t)) == reg) { + if (code.get(t + 1).definition instanceof KillIns) { + if (code.get(t + 1).operands[0] == reg) { + ConvertOutput assignment = toSourceOutput(thisHasDefaultToPrimitive, lineStartItem, path, part, processJumps, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, abc, body, ip + 2, t - 1, localRegNames, fullyQualifiedNames, visited, localRegAssigmentIps, refs); + if (!assignment.output.isEmpty()) { + GraphTargetItem tar = assignment.output.remove(assignment.output.size() - 1); + tar.firstPart = part; + stack.push(tar); + ip = t + 2; + + continue iploop; + } + } + } + } + } + } + if (!isKilled(reg, 0, end)) { + GraphTargetItem vx = stack.pop().getThroughDuplicate(); + int dupCnt = 1; + for (int i = ip - 1; i >= start; i--) { + if (code.get(i).definition instanceof DupIns) { + if (stack.isEmpty()) { + break; // FIXME?o + } + stack.pop(); + dupCnt++; + //stack.push(v); + } else { + break; + } + } + for (int i = 0; i < dupCnt; i++) { + stack.push(new LocalRegAVM2Item(ins, (AVM2Instruction) lineStartItem.getVal(), reg, vx)); + } + stack.push(vx); + } else { + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); + } + ip++; + break; + //} + + } else { + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); + ip++; + break; + //throw new ConvertException("Unknown pattern after DUP:" + insComparsion.toString()); + } + } while (ins.definition instanceof DupIns); + } else if ((ins.definition instanceof ReturnValueIns) || (ins.definition instanceof ReturnVoidIns) || (ins.definition instanceof ThrowIns)) { + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); + //ip = end + 1; + break; + } else if (ins.definition instanceof NewFunctionIns) { + String functionName = ""; + if ((ip >= start + 2) && (ip <= end - 4)) { + AVM2Instruction prev2 = code.get(ip - 2); + if (prev2.definition instanceof NewObjectIns) { + if (prev2.operands[0] == 0) { + if (code.get(ip - 1).definition instanceof PushWithIns) { + boolean hasDup = false; + int plus = 0; + if (code.get(ip + 1).definition instanceof DupIns) { + hasDup = true; + plus = 1; + } + AVM2Instruction psco = code.get(ip + 1 + plus); + if (psco.definition instanceof GetScopeObjectIns) { + if (psco.operands[0] == scopeStack.size() - 1) { + if (code.get(ip + plus + 2).definition instanceof SwapIns) { + if (code.get(ip + plus + 4).definition instanceof PopScopeIns) { + if (code.get(ip + plus + 3).definition instanceof SetPropertyIns) { + functionName = abc.constants.getMultiname(code.get(ip + plus + 3).operands[0]).getName(abc.constants, fullyQualifiedNames, true); + scopeStack.pop();// with + output.remove(output.size() - 1); // with + ip = ip + plus + 4; // +1 below + } + } + } + } + } + } + } + } + } + // What to do when hasDup is false? + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); + NewFunctionAVM2Item nft = (NewFunctionAVM2Item) stack.peek(); + nft.functionName = functionName; + ip++; + } else { + try { + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); + } catch (RuntimeException re) { + /*String last=""; + int len=5; + for(int i=(ip-len<0?0:ip-len);i maxRegister) { + maxRegister = regId; + } + } + return maxRegister + 1; + } + + public HashMap getLocalRegTypes(AVM2ConstantPool constants, List fullyQualifiedNames) { + HashMap ret = new HashMap<>(); + AVM2Instruction prev = null; + for (AVM2Instruction ins : code) { + if (ins.definition instanceof SetLocalTypeIns) { + if (prev != null) { + if (prev.definition instanceof CoerceOrConvertTypeIns) { + ret.put(((SetLocalTypeIns) ins.definition).getRegisterId(ins), ((CoerceOrConvertTypeIns) prev.definition).getTargetType(constants, prev)); + } + } + } + prev = ins; + } + return ret; + + } + + private class Slot { + + public final GraphTargetItem scope; + + public final Multiname multiname; + + public Slot(GraphTargetItem scope, Multiname multiname) { + this.scope = scope; + this.multiname = multiname; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Slot) { + Slot slot = (Slot) obj; + return (slot.scope.getThroughRegister() == scope.getThroughRegister()) + && (slot.multiname == multiname); + } + return false; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 59 * hash + (scope != null ? Objects.hashCode(scope.getThroughRegister()) : 0); + hash = 59 * hash + Objects.hashCode(multiname); + return hash; + } + } + + public void initToSource() { + toSourceCount = 0; + } + + private GraphTargetItem handleDeclareReg(int minreg, GraphTargetItem assignment, DeclarationAVM2Item[] declaredRegisters, List declaredSlots, int reg) { + + //do not add declarations for reserved local registers like function arguments + if (reg < minreg) { + return assignment; + } + GraphTargetItem vtype = TypeItem.UNBOUNDED; + if (assignment.value instanceof ConvertAVM2Item) { + vtype = ((ConvertAVM2Item) assignment.value).type; + } + + if (vtype.equals(TypeItem.UNBOUNDED) && (assignment.value instanceof CoerceAVM2Item)) { + vtype = ((CoerceAVM2Item) assignment.value).typeObj; + } + if (vtype.equals(TypeItem.UNBOUNDED) && (assignment.value instanceof SimpleValue) && ((SimpleValue) assignment.value).isSimpleValue()) { + vtype = assignment.value.returnType(); + } + + if (declaredRegisters[reg] == null) { + declaredRegisters[reg] = new DeclarationAVM2Item(assignment, vtype); + if (assignment instanceof SetTypeAVM2Item) { + ((SetTypeAVM2Item) assignment).setDeclaration(declaredRegisters[reg]); + } + return declaredRegisters[reg]; + } + + if (declaredRegisters[reg].type == TypeItem.UNBOUNDED) { + + } else if (!declaredRegisters[reg].type.equals(vtype)) { //already declared with different type + declaredRegisters[reg].type = TypeItem.UNBOUNDED; + } + + if (assignment instanceof SetTypeAVM2Item) { + ((SetTypeAVM2Item) assignment).setDeclaration(declaredRegisters[reg]); + } + + return assignment; + } + + private GraphTargetItem injectDeclarations(int minreg, GraphTargetItem ti, DeclarationAVM2Item[] declaredRegisters, List declaredSlots, List declaredSlotsDec, ABC abc, MethodBody body) { + if (ti.value != null) { + ti.value = injectDeclarations(minreg, ti.value, declaredRegisters, declaredSlots, declaredSlotsDec, abc, body); + } + //TODO: walk whole tree... some walker? + if (ti instanceof IfItem) { + ((IfItem) ti).expression = injectDeclarations(minreg, ((IfItem) ti).expression, declaredRegisters, declaredSlots, declaredSlotsDec, abc, body); + } + if (ti instanceof BinaryOpItem) { + ((BinaryOpItem) ti).leftSide = injectDeclarations(minreg, ((BinaryOpItem) ti).leftSide, declaredRegisters, declaredSlots, declaredSlotsDec, abc, body); + ((BinaryOpItem) ti).rightSide = injectDeclarations(minreg, ((BinaryOpItem) ti).rightSide, declaredRegisters, declaredSlots, declaredSlotsDec, abc, body); + } + if (ti instanceof ForEachInAVM2Item) { + ForEachInAVM2Item fei = (ForEachInAVM2Item) ti; + if (fei.expression.object instanceof LocalRegAVM2Item) { + int reg = ((LocalRegAVM2Item) fei.expression.object).regIndex; + if (declaredRegisters[reg] == null) { + fei.expression.object = handleDeclareReg(minreg, fei.expression.object, declaredRegisters, declaredSlots, reg); + } + } + } + if (ti instanceof ForInAVM2Item) { + ForInAVM2Item fi = (ForInAVM2Item) ti; + if (fi.expression.object instanceof LocalRegAVM2Item) { + int reg = ((LocalRegAVM2Item) fi.expression.object).regIndex; + fi.expression.object = handleDeclareReg(minreg, fi.expression.object, declaredRegisters, declaredSlots, reg); + //nowdeclaredRegs.add(reg); + + } + } + if (ti instanceof Block) { + Block bl = (Block) ti; + for (List s : bl.getSubs()) { + injectDeclarations(minreg, s, declaredRegisters, declaredSlots, declaredSlotsDec, abc, body); + } + } + if (ti instanceof SetLocalAVM2Item) { + int reg = ((SetLocalAVM2Item) ti).regIndex; + ti = handleDeclareReg(minreg, ti, declaredRegisters, declaredSlots, reg); + return ti; + } + if (ti instanceof SetSlotAVM2Item) { + SetSlotAVM2Item ssti = (SetSlotAVM2Item) ti; + Slot sl = new Slot(ssti.scope, ssti.slotName); + if (!declaredSlots.contains(sl)) { + GraphTargetItem type = TypeItem.UNBOUNDED; + for (int t = 0; t < body.traits.traits.size(); t++) { + if (body.traits.traits.get(t).getName(abc) == sl.multiname) { + if (body.traits.traits.get(t) instanceof TraitSlotConst) { + type = PropertyAVM2Item.multinameToType(((TraitSlotConst) body.traits.traits.get(t)).type_index, abc.constants); + } + } + } + DeclarationAVM2Item d = new DeclarationAVM2Item(ti, type); + ssti.setDeclaration(d); + declaredSlotsDec.add(d); + declaredSlots.add(sl); + return d; + //nowdeclaredSlots.add(sl); + } else { + int idx = declaredSlots.indexOf(sl); + ssti.setDeclaration(declaredSlotsDec.get(idx)); + } + } + return ti; + } + + private void injectDeclarations(int minreg, List list, DeclarationAVM2Item[] declaredRegisters, List declaredSlots, List declaredSlotsDec, ABC abc, MethodBody body) { + //List nowdeclaredRegs=new ArrayList<>(); + //List nowdeclaredSlots=new ArrayList<>(); + for (int i = 0; i < list.size(); i++) { + GraphTargetItem ti = list.get(i); + GraphTargetItem ti2 = injectDeclarations(minreg, ti, declaredRegisters, declaredSlots, declaredSlotsDec, abc, body); + if (ti != ti2) { + list.set(i, ti2); + } + } + + /* + //undeclare registers at the end of the block? + for(int reg:nowdeclaredRegs){ + declaredRegisters[reg] = false; + } + + for(Slot s:nowdeclaredSlots){ + declaredSlots.remove(s); + }*/ + } + + public List toGraphTargetItems(boolean thisHasDefaultToPrimitive, ConvertData convertData, String path, int methodIndex, boolean isStatic, int scriptIndex, int classIndex, ABC abc, MethodBody body, HashMap localRegNames, ScopeStack scopeStack, int initializerType, List fullyQualifiedNames, List initTraits, int staticOperation, HashMap localRegAssigmentIps, HashMap> refs) throws InterruptedException { + initToSource(); + List list; + HashMap localRegs = new HashMap<>(); + + int regCount = getRegisterCount(); + for (int i = 0; i < regCount; i++) { + localRegs.put(0, new UndefinedAVM2Item(null, null)); + } + + //try { + list = AVM2Graph.translateViaGraph(path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs, thisHasDefaultToPrimitive); + + if (initTraits != null) { + loopi: + for (int i = 0; i < list.size(); i++) { + GraphTargetItem ti = list.get(i); + if ((ti instanceof InitPropertyAVM2Item) || (ti instanceof SetPropertyAVM2Item)) { + int multinameIndex = 0; + GraphTargetItem value = null; + if (ti instanceof InitPropertyAVM2Item) { + multinameIndex = ((InitPropertyAVM2Item) ti).propertyName.multinameIndex; + value = ((InitPropertyAVM2Item) ti).value; + } + if (ti instanceof SetPropertyAVM2Item) { + multinameIndex = ((FullMultinameAVM2Item) ((SetPropertyAVM2Item) ti).propertyName).multinameIndex; + value = ((SetPropertyAVM2Item) ti).value; + } + Multiname m = abc.constants.getMultiname(multinameIndex); + for (Traits ts : initTraits) { + for (Trait t : ts.traits) { + Multiname tm = abc.constants.getMultiname(t.name_index); + if (tm != null && tm.equals(m)) { + if ((t instanceof TraitSlotConst)) { + if (((TraitSlotConst) t).isConst() || initializerType == GraphTextWriter.TRAIT_CLASS_INITIALIZER || initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) { + TraitSlotConst tsc = (TraitSlotConst) t; + if (value != null && !convertData.assignedValues.containsKey(tsc)) { + + if (value instanceof NewFunctionAVM2Item) { + NewFunctionAVM2Item f = (NewFunctionAVM2Item) value; + f.functionName = tsc.getName(abc).getName(abc.constants, fullyQualifiedNames, true); + } + AssignedValue av = new AssignedValue(value, initializerType, methodIndex); + convertData.assignedValues.put(tsc, av); + list.remove(i); + i--; + continue; + } + } + break; + } + } + } + } + } else { + // In obfuscated code, SetLocal instructions comes first + //break; + } + } + } + if (initializerType == GraphTextWriter.TRAIT_CLASS_INITIALIZER || initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) { + List newList = new ArrayList<>(); + for (GraphTargetItem ti : list) { + if (!(ti instanceof ReturnVoidAVM2Item)) { + if (!(ti instanceof InitPropertyAVM2Item)) { + newList.add(ti); + } + } + } + list = newList; + if (list.isEmpty()) { + return list; + } + } + // Declarations + + DeclarationAVM2Item d[] = new DeclarationAVM2Item[regCount]; + + int param_types[] = abc.method_info.get(body.method_info).param_types; + int r = 1; + for (int i = 0; i < param_types.length; i++) { + GraphTargetItem type; + if (param_types[i] == 0) { + type = TypeItem.UNBOUNDED; + } else { + type = new TypeItem(abc.constants.getMultiname(param_types[i]).getNameWithNamespace(abc.constants)); + } + if (d.length > r) { + d[r] = new DeclarationAVM2Item(new SetLocalAVM2Item(null, null, r, new NullAVM2Item(null, null)), type); + } + r++; + } + if (abc.method_info.get(body.method_info).flagNeed_arguments()) { + if (d.length > r) { + d[r] = new DeclarationAVM2Item(new SetLocalAVM2Item(null, null, r, new NullAVM2Item(null, null)), TypeItem.ARRAY /*?*/); + } + r++; + } + if (abc.method_info.get(body.method_info).flagNeed_rest()) { + if (d.length > r) { + d[r] = new DeclarationAVM2Item(new SetLocalAVM2Item(null, null, r, new NullAVM2Item(null, null)), TypeItem.ARRAY/*?*/); + } + r++; + } + // + + //int minreg = abc.method_info.get(body.method_info).getMaxReservedReg() + 1; + injectDeclarations(1, list, d, new ArrayList<>(), new ArrayList<>(), abc, body); + + int lastPos = list.size() - 1; + if (lastPos < 0) { + lastPos = 0; + } + if ((list.size() > lastPos) && (list.get(lastPos) instanceof ScriptEndItem)) { + lastPos--; + } + if (lastPos < 0) { + lastPos = 0; + } + if ((list.size() > lastPos) && (list.get(lastPos) instanceof ReturnVoidAVM2Item)) { + list.remove(lastPos); + } + + return list; + } + + public void updateOffsets(OffsetUpdater updater, MethodBody body) { + for (int i = 0; i < code.size(); i++) { + AVM2Instruction ins = code.get(i); + if (ins.definition instanceof LookupSwitchIns) { + long target = ins.getAddress() + ins.operands[0]; + ins.operands[0] = updater.updateOperandOffset(ins.getAddress(), target, ins.operands[0]); + for (int k = 2; k < ins.operands.length; k++) { + target = ins.getAddress() + ins.operands[k]; + ins.operands[k] = updater.updateOperandOffset(ins.getAddress(), target, ins.operands[k]); + } + } else /*for (int j = 0; j < ins.definition.operands.length; j++) { + if (ins.definition.operands[j] == AVM2Code.DAT_OFFSET) { + long target = ins.offset + ins.getBytes().length + ins.operands[j]; + ins.operands[j] = updater.updateOperandOffset(target, ins.operands[j]); + } + }*/ //Faster, but not so universal + { + if (ins.definition instanceof IfTypeIns) { + long target = ins.getTargetAddress(); + try { + ins.operands[0] = updater.updateOperandOffset(ins.getAddress(), target, ins.operands[0]); + } catch (ConvertException cex) { + throw new ConvertException("Invalid offset (" + ins + ")", i); + } + } + } + ins.setAddress(updater.updateInstructionOffset(ins.getAddress())); + } + + for (ABCException ex : body.exceptions) { + ex.start = updater.updateOperandOffset(-1, ex.start, ex.start); + ex.end = updater.updateOperandOffset(-1, ex.end, ex.end); + ex.target = updater.updateOperandOffset(-1, ex.target, ex.target); + } + } + + public void fixJumps(final String path, MethodBody body) throws InterruptedException { + if (code.isEmpty()) { + return; + } + final List insAddrToRemove = new ArrayList<>(); + final long endOffset = getEndOffset(); + updateOffsets(new OffsetUpdater() { + + @Override + public long updateInstructionOffset(long address) { + return address; + } + + @Override + public int updateOperandOffset(long insAddr, long targetAddress, int offset) { + if (targetAddress > endOffset || targetAddress < 0 || adr2posNoEx(targetAddress) < 0) { + insAddrToRemove.add(insAddr); + } + return offset; + } + + }, body); + + boolean someIgnored = false; + for (Long insAddr : insAddrToRemove) { + int pos = adr2posNoEx(insAddr); + if (pos > -1) { + code.get(pos).setIgnored(true, 0); + someIgnored = true; + } + } + if (someIgnored) { + logger.log(Level.WARNING, path + ": One or more invalid jump offsets found in the code. Those instructions were ignored."); + } + removeIgnored(body); + } + + public void checkValidOffsets(MethodBody body) { + updateOffsets(new OffsetUpdater() { + + @Override + public long updateInstructionOffset(long address) { + adr2pos(address); + return address; + } + + @Override + public int updateOperandOffset(long insAddr, long targetAddress, int offset) { + /*if (insAddr == -1) { + return offset; + }*/ + adr2pos(targetAddress); + return offset; + } + + }, body); + } + + public void removeInstruction(int pos, MethodBody body) { + if ((pos < 0) || (pos >= code.size())) { + throw new IndexOutOfBoundsException(); + } + + AVM2Instruction ins = code.get(pos); + final long remOffset = ins.getAddress(); + int bc = ins.getBytesLength(); + + final int byteCount = bc; + updateOffsets(new OffsetUpdater() { + @Override + public long updateInstructionOffset(long address) { + if (address > remOffset) { + return address - byteCount; + } + return address; + } + + @Override + public int updateOperandOffset(long jumpInsAddr, long jumpTargetAddr, int jumpOffset) { + /* + a:jump d: + b: + c:X + d: + */ + if (jumpTargetAddr > remOffset && jumpInsAddr < remOffset) { + return jumpOffset - byteCount; + } + /* + a:X1 + b:X2 + c: + d:jump a: + */ + if (jumpTargetAddr <= remOffset && jumpInsAddr > remOffset) { + return jumpOffset + byteCount; + } + + return jumpOffset; + } + }, body); + code.remove(pos); + //checkValidOffsets(body); + } + + /** + * Inserts instruction at specified point. Handles offsets properly. Note: + * If newinstruction is jump, the offset operand must be handled properly by + * caller. All old jump offsets to pos are targeted before new instruction. + * + * @param pos Position in the list + * @param instruction Instruction False means before new instruction + * @param body Method body (used for try handling) + */ + public void insertInstruction(int pos, AVM2Instruction instruction, MethodBody body) { + insertInstruction(pos, instruction, false, body); + } + + /** + * Replaces instruction by another. Properly handles offsets. Note: If + * newinstruction is jump, the offset operand must be handled properly by + * caller. + * + * @param pos + * @param instruction + * @param body + */ + public void replaceInstruction(int pos, AVM2Instruction instruction, MethodBody body) { + AVM2Instruction oldInstruction = code.get(pos); + instruction.setAddress(oldInstruction.getAddress()); + int oldByteCount = oldInstruction.getBytesLength(); + int newByteCount = instruction.getBytesLength(); + int byteDelta = newByteCount - oldByteCount; + + if (byteDelta != 0) { + updateOffsets(new OffsetUpdater() { + + @Override + public long updateInstructionOffset(long address) { + if (address > instruction.getAddress()) { + return address + byteDelta; + } + return address; + } + + @Override + public int updateOperandOffset(long insAddr, long targetAddress, int offset) { + if (targetAddress > instruction.getAddress() && insAddr <= instruction.getAddress()) { + return offset + byteDelta; + } + if (targetAddress <= instruction.getAddress() && insAddr > instruction.getAddress()) { + return offset - byteDelta; + } + return offset; + } + }, body); + } + code.set(pos, instruction); + } + + /** + * Inserts instruction at specified point. Handles offsets properly. Note: + * If newinstruction is jump, the offset operand must be handled properly by + * caller. + * + * @param pos Position in the list + * @param instruction Instruction + * @param mapOffsetsAfterIns Map all jumps to the pos after new instruction? + * False means before new instruction + * @param body Method body (used for try handling) + */ + public void insertInstruction(int pos, AVM2Instruction instruction, boolean mapOffsetsAfterIns, MethodBody body) { + //checkValidOffsets(body); + if (pos < 0) { + pos = 0; + } + if (pos > code.size()) { + pos = code.size(); + } + final int byteCount = instruction.getBytesLength(); + if (pos == code.size()) { + instruction.setAddress(code.get(pos - 1).getAddress() + code.get(pos - 1).getBytesLength()); + } else { + instruction.setAddress(code.get(pos).getAddress()); + } + final long x = instruction.getAddress(); + updateOffsets(new OffsetUpdater() { + + @Override + public long updateInstructionOffset(long offset) { + if (offset >= x) { + return offset + byteCount; + } + return offset; + } + + @Override + public int updateOperandOffset(long j, long t, int offset_jt) { + + /* + j:jump t: + n: + n: + x:# + t: + */ + if (((t > x) || (mapOffsetsAfterIns && (t == x))) && (j < x)) { + return offset_jt + byteCount; + } + /* + t: + x:# + n: + n: + j:jump t: + */ + if (((t < x) || (mapOffsetsAfterIns && (t == x))) && (j > x)) { + return offset_jt - byteCount; + } + + /* + t: + n: + n: + j:x: # jump t: + */ + if ((j == x) && (t < x)) { + return offset_jt - byteCount; + } + + return offset_jt; + } + }, body); + instruction.setAddress(x); + code.add(pos, instruction); + //checkValidOffsets(body); + } + + public int removeTraps(Trait trait, int methodInfo, MethodBody body, ABC abc, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException { + SWFDecompilerPlugin.fireAvm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); + try (Statistics s = new Statistics("AVM2DeobfuscatorGetSet")) { + new AVM2DeobfuscatorGetSet().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); + } + try (Statistics s = new Statistics("AVM2DeobfuscatorSimple")) { + new AVM2DeobfuscatorSimpleOld().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); + } + try (Statistics s = new Statistics("AVM2DeobfuscatorRegisters")) { + new AVM2DeobfuscatorRegistersOld().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); + } + try (Statistics s = new Statistics("AVM2DeobfuscatorJumps")) { + new AVM2DeobfuscatorJumps().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); + } + return 1; + } + + private void handleRegister(CodeStats stats, int reg) { + if (reg + 1 > stats.maxlocal) { + stats.maxlocal = reg + 1; + } + } + + private boolean walkCode(CodeStats stats, int pos, int stack, int scope, ABC abc) { + while (pos < code.size()) { + AVM2Instruction ins = code.get(pos); + if (stats.instructionStats[pos].seen) { + // check stack mismatch here + return true; + } + + if (ins.definition instanceof NewFunctionIns) { + MethodBody innerBody = abc.findBody(ins.operands[0]); + innerBody.autoFillStats(abc, stats.initscope + (stats.has_activation ? 1 : 0), false); + } + + stats.instructionStats[pos].seen = true; + stats.instructionStats[pos].stackpos = stack; + stats.instructionStats[pos].scopepos = scope; + + int stackDelta = ins.definition.getStackDelta(ins, abc); + int scopeDelta = ins.definition.getScopeStackDelta(ins, abc); + int oldStack = stack; + + //+" deltaScope:"+(scopeDelta>0?"+"+scopeDelta:scopeDelta)+" stack:"+stack+" scope:"+scope); + stack += stackDelta; + scope += scopeDelta; + + stats.instructionStats[pos].stackpos_after = stack; + stats.instructionStats[pos].scopepos_after = scope; + + if (stack > stats.maxstack) { + stats.maxstack = stack; + } + if (scope > stats.maxscope) { + stats.maxscope = scope; + } + + //System.out.println("stack "+oldStack+(stackDelta>=0?"+"+stackDelta:stackDelta)+" max:"+stats.maxstack+" "+ins); + if ((ins.definition instanceof DXNSIns) || (ins.definition instanceof DXNSLateIns)) { + stats.has_set_dxns = true; + } + if (ins.definition instanceof NewActivationIns) { + stats.has_activation = true; + } + if (ins.definition instanceof SetLocalTypeIns) { + handleRegister(stats, ((SetLocalTypeIns) ins.definition).getRegisterId(ins)); + } else if (ins.definition instanceof GetLocalTypeIns) { + handleRegister(stats, ((GetLocalTypeIns) ins.definition).getRegisterId(ins)); + } else { + for (int i = 0; i < ins.definition.operands.length; i++) { + int op = ins.definition.operands[i]; + if (op == DAT_LOCAL_REG_INDEX) { + handleRegister(stats, ins.operands[i]); + } + } + } + if (ins.definition instanceof ReturnValueIns) { + // check stack=1 + return true; + } + if (ins.definition instanceof ReturnVoidIns) { + // check stack=0 + return true; + } + if (ins.definition instanceof JumpIns) { + try { + pos = adr2pos(ins.getTargetAddress()); + continue; + } catch (ConvertException ex) { + return false; + } + } else if (ins.definition instanceof IfTypeIns) { + try { + int newpos = adr2pos(ins.getTargetAddress()); + walkCode(stats, newpos, stack, scope, abc); + } catch (ConvertException ex) { + return false; + } + } + if (ins.definition instanceof LookupSwitchIns) { + for (int i = 0; i < ins.operands.length; i++) { + if (i == 1) { + continue; + } + try { + int newpos = adr2pos(pos2adr(pos) + ins.operands[i]); + if (!walkCode(stats, newpos, stack, scope, abc)) { + return false; + } + } catch (ConvertException ex) { + return false; + } + } + } + pos++; + } + return true; + } + + public CodeStats getStats(ABC abc, MethodBody body, int initScope) { + CodeStats stats = new CodeStats(this); + stats.initscope = initScope; + if (!walkCode(stats, 0, 0, initScope, abc)) { + return null; + } + int scopePos = -1; + int prevStart = 0; + for (int e = 0; e < body.exceptions.length; e++) { + ABCException ex = body.exceptions[e]; + try { + if (scopePos == -1) { + scopePos = stats.instructionStats[adr2pos(ex.end) - 1].scopepos_after; + } + List visited = new ArrayList<>(); + for (int i = 0; i < stats.instructionStats.length; i++) { + if (stats.instructionStats[i].seen) { + visited.add(i); + } + } + if (!walkCode(stats, adr2pos(ex.target), 1 + (ex.isFinally() ? 1 : 0), scopePos, abc)) { + return null; + } + int maxIp = 0; + // searching for visited instruction in second run which has maximum position + for (int i = 0; i < stats.instructionStats.length; i++) { + if (stats.instructionStats[i].seen && !visited.contains(i)) { + maxIp = i; + } + } + scopePos = stats.instructionStats[maxIp].scopepos_after; + int stackPos = stats.instructionStats[maxIp].stackpos_after; + int nextIp = maxIp + 1; + if (code.get(maxIp).definition instanceof JumpIns) { + nextIp = adr2pos(pos2adr(nextIp) + code.get(maxIp).operands[0]); + } + if (nextIp < stats.instructionStats.length) { + InstructionStats nextIpStat = stats.instructionStats[nextIp]; + int origScopePos = nextIpStat.scopepos; + int origStackPos = nextIpStat.stackpos; + + if (prevStart == ex.start && ex.isFinally() && !code.get(nextIp).isExit() && nextIpStat.seen) { + for (int i = 0; i < stats.instructionStats.length; i++) { + stats.instructionStats[i].seen = false; + } + // Rerun rest with new scopePos, stackPos + if (!walkCode(stats, nextIp, origStackPos + 1/*magic!*/, scopePos - 1 /*magic!*/, abc)) { + return null; + } + scopePos--; + } + } + prevStart = ex.start; + } catch (ConvertException ex1) { + // ignore + } + } + //stats.maxscope+=initScope; + return stats; + } + + private void visitCode(int ip, int lastIp, HashMap> refs) throws InterruptedException { + List toVisit = new ArrayList<>(); + List toVisitLast = new ArrayList<>(); + toVisit.add(ip); + toVisitLast.add(lastIp); + while (!toVisit.isEmpty()) { + if (Thread.currentThread().isInterrupted()) { + throw new InterruptedException(); + } + ip = toVisit.remove(0); + lastIp = toVisitLast.remove(0); + while (ip < code.size()) { + if (!refs.containsKey(ip)) { + refs.put(ip, new ArrayList<>()); + } + refs.get(ip).add(lastIp); + lastIp = ip; + if (refs.get(ip).size() > 1) { + break; + } + AVM2Instruction ins = code.get(ip); + if (ins.definition instanceof ThrowIns) { + break; + } + if (ins.definition instanceof ReturnValueIns) { + break; + } + if (ins.definition instanceof ReturnVoidIns) { + break; + } + if (ins.definition instanceof LookupSwitchIns) { + try { + for (int i = 2; i < ins.operands.length; i++) { + toVisit.add(adr2pos(pos2adr(ip) + ins.operands[i])); + toVisitLast.add(ip); + } + ip = adr2pos(pos2adr(ip) + ins.operands[0]); + continue; + } catch (ConvertException ex) { + } + } + if (ins.definition instanceof JumpIns) { + try { + ip = adr2pos(ins.getTargetAddress()); + continue; + } catch (ConvertException ex) { + logger.log(Level.FINE, null, ex); + } + } else if (ins.definition instanceof IfTypeIns) { + try { + toVisit.add(adr2pos(ins.getTargetAddress())); + toVisitLast.add(ip); + } catch (ConvertException ex) { + logger.log(Level.FINE, null, ex); + } + } + ip++; + } + }; + } + + public HashMap> visitCode(MethodBody body) throws InterruptedException { + HashMap> refs = new HashMap<>(); + for (int i = 0; i < code.size(); i++) { + refs.put(i, new ArrayList<>()); + } + visitCode(0, 0, refs); + int pos = 0; + for (ABCException e : body.exceptions) { + pos++; + try { + visitCode(adr2pos(e.start, true), adr2pos(e.start, true) - 1, refs); + visitCode(adr2pos(e.start, true), -1, refs); + visitCode(adr2pos(e.target), adr2pos(e.end, true), refs); + visitCode(adr2pos(e.end, true), -pos, refs); + } catch (ConvertException ex) { + logger.log(Level.SEVERE, "Visitcode error", ex); + } + } + return refs; + } + + public void removeIgnored(MethodBody body) throws InterruptedException { + //System.err.println("removing ignored..."); + for (int i = 0; i < code.size(); i++) { + if (code.get(i).isIgnored()) { + removeInstruction(i, body); + i--; + } + } + //System.err.println("/ignored removed"); + } + + public int removeDeadCode(MethodBody body) throws InterruptedException { + HashMap> refs = visitCode(body); + int cnt = 0; + for (int i = code.size() - 1; i >= 0; i--) { + if (refs.get(i).isEmpty()) { + code.get(i).setIgnored(true, 0); + cnt++; + } + } + + removeIgnored(body); + + for (int i = code.size() - 1; i >= 0; i--) { + AVM2Instruction ins = code.get(i); + if (ins.definition instanceof JumpIns) { + if (ins.operands[0] == 0) { + ins.setIgnored(true, 0); + cnt++; + } + } + } + + removeIgnored(body); + + return cnt; + } + + public boolean inlineJumpExit() { + boolean modified = false; + int csize = code.size(); + for (int i = 0; i < csize; i++) { + AVM2Instruction ins = code.get(i); + int insLen = code.get(i).getBytesLength(); + long ofs = pos2adr(i); + if (ins.definition instanceof JumpIns) { + long targetOfs = ofs + insLen + ins.operands[0]; + try { + int ni = adr2pos(targetOfs); + if (ni < code.size() && ni > -1) { + AVM2Instruction ins2 = code.get(ni); + if (ins2.isExit()) { + code.set(i, new AVM2Instruction(ofs, ins2.definition, ins2.operands)); + modified = true; + } + } + } catch (ConvertException ex) { + //ignore + } + } + } + + return modified; + } + + private static int getMostCommonIp(AVM2GraphSource code, List branches) { + List> reachable = new ArrayList<>(); + for (int i = 0; i < branches.size(); i++) { + List r = new ArrayList<>(); + getReachableIps(code, branches.get(i), r); + } + + int commonLevel; + Map levelMap = new HashMap<>(); + for (List first : reachable) { + int maxclevel = 0; + Set visited = new HashSet<>(); + for (Integer p : first) { + if (visited.contains(p)) { + continue; + } + visited.add(p); + boolean common = true; + commonLevel = 1; + for (List r : reachable) { + if (r == first) { + continue; + } + if (r.contains(p)) { + commonLevel++; + } + } + if (commonLevel <= maxclevel) { + continue; + } + maxclevel = commonLevel; + if (levelMap.containsKey(p)) { + if (levelMap.get(p) > commonLevel) { + commonLevel = levelMap.get(p); + } + } + levelMap.put(p, commonLevel); + if (common) { + //return p; + } + } + } + for (int i = reachable.size() - 1; i >= 2; i--) { + for (Integer p : levelMap.keySet()) { + if (levelMap.get(p) == i) { + return p; + } + } + } + for (Integer p : levelMap.keySet()) { + if (levelMap.get(p) == branches.size()) { + return p; + } + } + return -1; + } + + public static void getReachableIps(AVM2GraphSource code, int ip, List reachable) { + do { + if (reachable.contains(ip)) { + return; + } + reachable.add(ip); + GraphSourceItem ins = code.get(ip); + if (ins.isJump() || ins.isBranch()) { + List branches = ins.getBranches(code); + for (int i = 1; i < branches.size(); i++) { + getReachableIps(code, branches.get(i), reachable); + } + ip = branches.get(0); + continue; + } + ip++; + } while (ip < code.size()); + } + + public static boolean isDirectAncestor(int currentIp, int ancestor, HashMap> refs) { + return isDirectAncestor(currentIp, ancestor, refs, new ArrayList<>()); + } + + private static boolean isDirectAncestor(int currentIp, int ancestor, HashMap> refs, List visited) { + if (currentIp == -1) { + return true; + } + do { + if (currentIp == ancestor) { + return true; + } + if (currentIp == 0) { + return false; + } + if (visited.contains(currentIp)) { + return true; + } + visited.add(currentIp); + if (refs.containsKey(currentIp)) { + List currentRefs = refs.get(currentIp); + if ((currentRefs != null) && (!currentRefs.isEmpty())) { + for (int i = 1; i < currentRefs.size(); i++) { + if (!isDirectAncestor(currentRefs.get(i), ancestor, refs, visited)) { + return false; + } + } + currentIp = currentRefs.get(0); + continue; + } + } + currentIp--; + } while (currentIp >= 0); + return false; + } + + public static boolean getPreviousReachableIps(int currentIp, HashMap> refs, Set reachable, Set visited) { + do { + if (visited.contains(currentIp)) { + return false; + } + reachable.add(currentIp); + visited.add(currentIp); + if (refs.containsKey(currentIp)) { + List currentRefs = refs.get(currentIp); + if ((currentRefs != null) && (!currentRefs.isEmpty())) { + if (currentRefs.size() == 1) { + currentIp = currentRefs.get(0); + continue; + } + boolean r = false; + for (int i = 0; i < currentRefs.size(); i++) { + Set nr = new HashSet<>(); + boolean v = getPreviousReachableIps(currentRefs.get(i), refs, nr, visited); + if ((!v) || nr.contains(0)) { + reachable.addAll(nr); + } + r = r || v; + } + return r; + } + } + currentIp--; + } while (currentIp >= 0); + return true; + } + + @Override + public AVM2Code clone() { + try { + AVM2Code ret = (AVM2Code) super.clone(); + if (code != null) { + List codeCopy = new ArrayList<>(code.size()); + for (AVM2Instruction ins : code) { + codeCopy.add(ins.clone()); + } + ret.code = codeCopy; + } + + ret.killedRegs = new HashMap<>(); + return ret; + } catch (CloneNotSupportedException ex) { + throw new RuntimeException(); + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/XMLAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/XMLAVM2Item.java index 8292763e2..b089505c6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/XMLAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/XMLAVM2Item.java @@ -1,61 +1,61 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.abc.avm2.model; - -import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.graph.DottedChain; -import com.jpexs.decompiler.graph.GraphSourceItem; -import com.jpexs.decompiler.graph.GraphTargetItem; -import com.jpexs.decompiler.graph.TypeItem; -import com.jpexs.decompiler.graph.model.LocalData; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class XMLAVM2Item extends AVM2Item { - - public List parts; - - public XMLAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, List parts) { - super(instruction, lineStartIns, NOPRECEDENCE); - this.parts = parts; - } - - @Override - public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { - for (GraphTargetItem part : parts) { - if (part instanceof StringAVM2Item) { - writer.append(((StringAVM2Item) part).getValue()); - } else { - part.toString(writer, localData); - } - } - return writer; - } - - @Override - public GraphTargetItem returnType() { - return new TypeItem(DottedChain.XML); - } - - @Override - public boolean hasReturnValue() { - return true; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.abc.avm2.model; + +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.DottedChain; +import com.jpexs.decompiler.graph.GraphSourceItem; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.TypeItem; +import com.jpexs.decompiler.graph.model.LocalData; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class XMLAVM2Item extends AVM2Item { + + public List parts; + + public XMLAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, List parts) { + super(instruction, lineStartIns, NOPRECEDENCE); + this.parts = parts; + } + + @Override + public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { + for (GraphTargetItem part : parts) { + if (part instanceof StringAVM2Item) { + writer.append(((StringAVM2Item) part).getValue()); + } else { + part.toString(writer, localData); + } + } + return writer; + } + + @Override + public GraphTargetItem returnType() { + return new TypeItem(DottedChain.XML); + } + + @Override + public boolean hasReturnValue() { + return true; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java index dcfde7578..d2a9d5df4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java @@ -1,475 +1,475 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.abc.types; - -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.ABCInputStream; -import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; -import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; -import com.jpexs.decompiler.flash.abc.avm2.CodeStats; -import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCode; -import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel; -import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; -import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.abc.types.traits.Traits; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; -import com.jpexs.decompiler.flash.helpers.NulWriter; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.decompiler.flash.types.annotations.SWFField; -import com.jpexs.decompiler.graph.DottedChain; -import com.jpexs.decompiler.graph.Graph; -import com.jpexs.decompiler.graph.GraphTargetItem; -import com.jpexs.decompiler.graph.ScopeStack; -import com.jpexs.decompiler.graph.model.LocalData; -import com.jpexs.helpers.CancellableWorker; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.MemoryInputStream; -import com.jpexs.helpers.stat.Statistics; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public final class MethodBody implements Cloneable { - - private static final Logger logger = Logger.getLogger(MethodBody.class.getName()); - - private static final String DEBUG_FIXED = null; - - @Internal - public boolean deleted; - - @Internal - boolean debugMode = false; - - public int method_info; - - public int max_stack; - - public int max_regs; - - public int init_scope_depth; - - public int max_scope_depth; - - @SWFField - private byte[] codeBytes; - - private AVM2Code code; - - public ABCException[] exceptions; - - public Traits traits; - - @Internal - public transient List convertedItems; - - @Internal - public transient Throwable convertException; - - @Internal - private ABC abc; - - public MethodBody() { - this.traits = new Traits(); - this.codeBytes = SWFInputStream.BYTE_ARRAY_EMPTY; - this.exceptions = new ABCException[0]; - this.abc = null; - } - - public void setAbc(ABC abc) { - this.abc = abc; - } - - public MethodBody(ABC abc, Traits traits, byte[] codeBytes, ABCException[] exceptions) { - this.traits = traits; - this.codeBytes = codeBytes; - this.exceptions = exceptions; - this.abc = abc; - } - - public synchronized void setCodeBytes(byte codeBytes[]) { - this.codeBytes = codeBytes; - this.code = null; - } - - public void setModified() { - this.codeBytes = null; - } - - public synchronized byte[] getCodeBytes() { - if (codeBytes != null) { - return codeBytes; - } else { - return code.getBytes(); - } - } - - public synchronized AVM2Code getCode() { - if (code == null) { - AVM2Code avm2Code; - try { - ABCInputStream ais = new ABCInputStream(new MemoryInputStream(codeBytes)); - avm2Code = new AVM2Code(ais, this); - avm2Code.removeWrongIndices(abc.constants); - } catch (UnknownInstructionCode | IOException ex) { - avm2Code = new AVM2Code(); - logger.log(Level.SEVERE, null, ex); - } - avm2Code.compact(); - code = avm2Code; - } - return code; - } - - public void setCode(AVM2Code code) { - this.code = code; - this.codeBytes = null; - } - - public List getExceptionEntries() { - List ret = new ArrayList<>(); - AVM2Code code = getCode(); - for (ABCException e : exceptions) { - ret.add(code.adr2pos(e.start, true)); - ret.add(code.adr2pos(e.end, true)); - ret.add(code.adr2pos(e.target)); - } - return ret; - } - - public void markOffsets() { - getCode().markOffsets(); - } - - @Override - public String toString() { - String s = ""; - s += "method_info=" + method_info + " max_stack=" + max_stack + " max_regs=" + max_regs + " scope_depth=" + init_scope_depth + " max_scope=" + max_scope_depth; - s += "\r\nCode:\r\n" + getCode().toString(); - return s; - } - - public int removeDeadCode(AVM2ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException { - return getCode().removeDeadCode(this); - } - - public int removeTraps(ABC abc, Trait trait, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException { - - return getCode().removeTraps(trait, method_info, this, abc, scriptIndex, classIndex, isStatic, path); - } - - public void deobfuscate(DeobfuscationLevel level, Trait trait, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException { - if (level == DeobfuscationLevel.LEVEL_REMOVE_DEAD_CODE) { - removeDeadCode(abc.constants, trait, abc.method_info.get(method_info)); - } else if (level == DeobfuscationLevel.LEVEL_REMOVE_TRAPS) { - removeTraps(abc, trait, scriptIndex, classIndex, isStatic, path); - } else if (level == DeobfuscationLevel.LEVEL_RESTORE_CONTROL_FLOW) { - removeTraps(abc, trait, scriptIndex, classIndex, isStatic, path); - } - - ((Tag) abc.parentTag).setModified(true); - } - - public void removeInstruction(int pos) { - getCode().removeInstruction(pos, this); - } - - /** - * Replaces instruction by another. Properly handles offsets. Note: If - * newinstruction is jump, the offset operand must be handled properly by - * caller. - * - * @param pos - * @param instruction - */ - public void replaceInstruction(int pos, AVM2Instruction instruction) { - getCode().replaceInstruction(pos, instruction, this); - } - - /** - * Inserts instruction at specified point. Handles offsets properly. Note: - * If newinstruction is jump, the offset operand must be handled properly by - * caller. All old jump offsets to pos are targeted before new instruction. - * - * @param pos Position in the list - * @param instruction Instruction False means before new instruction - */ - public void insertInstruction(int pos, AVM2Instruction instruction) { - getCode().insertInstruction(pos, instruction, this); - } - - public void insertAll(int pos, List list) { - for (AVM2Instruction ins : list) { - insertInstruction(pos++, ins); - } - } - - /** - * Inserts instruction at specified point. Handles offsets properly. Note: - * If newinstruction is jump, the offset operand must be handled properly by - * caller. - * - * @param pos Position in the list - * @param instruction Instruction - * @param mapOffsetsAfterIns Map all jumps to the pos after new instruction? - * False means before new instruction - */ - public void insertInstruction(int pos, AVM2Instruction instruction, boolean mapOffsetsAfterIns) { - getCode().insertInstruction(pos, instruction, mapOffsetsAfterIns, this); - } - - public int getLocalReservedCount() { - MethodInfo methodInfo = abc.method_info.get(this.method_info); - int pos = methodInfo.param_types.length + 1; - if (methodInfo.flagNeed_arguments()) { - pos++; - } - if (methodInfo.flagNeed_rest()) { - pos++; - } - return pos; - } - - public HashMap getLocalRegNames(ABC abc) { - HashMap ret = new HashMap<>(); - for (int i = 1; i <= abc.method_info.get(this.method_info).param_types.length; i++) { - String paramName = "param" + i; - if (abc.method_info.get(this.method_info).flagHas_paramnames() && Configuration.paramNamesEnable.get()) { - paramName = abc.constants.getString(abc.method_info.get(this.method_info).paramNames[i - 1]); - } - ret.put(i, paramName); - } - int pos = abc.method_info.get(this.method_info).param_types.length + 1; - if (abc.method_info.get(this.method_info).flagNeed_arguments()) { - ret.put(pos, "arguments"); - pos++; - } - if (abc.method_info.get(this.method_info).flagNeed_rest()) { - ret.put(pos, "rest"); - pos++; - } - - if (Configuration.getLocalNamesFromDebugInfo.get()) { - Map debugRegNames = getCode().getLocalRegNamesFromDebug(abc); - for (int k : debugRegNames.keySet()) { - ret.put(k, debugRegNames.get(k)); - } - } - return ret; - } - - public void convert(final ConvertData convertData, final String path, ScriptExportMode exportMode, final boolean isStatic, final int methodIndex, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final ScopeStack scopeStack, final int initializerType, final NulWriter writer, final List fullyQualifiedNames, final List initTraits, boolean firstLevel) throws InterruptedException { - if (debugMode) { - System.err.println("Decompiling " + path); - } - if (exportMode != ScriptExportMode.AS) { - getCode().toASMSource(abc.constants, trait, abc.method_info.get(this.method_info), this, exportMode, writer); - } else { - if ((DEBUG_FIXED != null && !path.endsWith(DEBUG_FIXED)) || (!Configuration.decompile.get())) { - writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine(); - return; - } - int timeout = Configuration.decompilationTimeoutSingleMethod.get(); - convertException = null; - try { - Callable callable = new Callable() { - @Override - public Void call() throws InterruptedException { - try (Statistics s1 = new Statistics("MethodBody.convert")) { - MethodBody converted = convertMethodBody(convertData, path, isStatic, scriptIndex, classIndex, abc, trait, scopeStack, initializerType != GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, fullyQualifiedNames, initTraits); - HashMap localRegNames = getLocalRegNames(abc); - List convertedItems1; - try (Statistics s = new Statistics("AVM2Code.toGraphTargetItems")) { - convertedItems1 = converted.getCode().toGraphTargetItems(convertData.thisHasDefaultToPrimitive, convertData, path, methodIndex, isStatic, scriptIndex, classIndex, abc, converted, localRegNames, scopeStack, initializerType, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap<>(), converted.getCode().visitCode(converted)); - } - try (Statistics s = new Statistics("Graph.graphToString")) { - Graph.graphToString(convertedItems1, writer, LocalData.create(abc.constants, localRegNames, fullyQualifiedNames)); - } - convertedItems = convertedItems1; - } - return null; - } - }; - if (firstLevel) { - CancellableWorker.call(callable, timeout, TimeUnit.SECONDS); - } else { - callable.call(); - } - } catch (InterruptedException ex) { - throw ex; - } catch (Exception | OutOfMemoryError | StackOverflowError ex) { - - convertException = ex; - Throwable cause = ex.getCause(); - if (ex instanceof ExecutionException && cause instanceof Exception) { - convertException = (Exception) cause; - } - if (convertException instanceof TimeoutException) { - logger.log(Level.SEVERE, "Decompilation timeout in: " + path, convertException); - } else { - logger.log(Level.SEVERE, "Decompilation error in: " + path, convertException); - } - - } - } - } - - public GraphTextWriter toString(final String path, ScriptExportMode exportMode, final ABC abc, final Trait trait, final GraphTextWriter writer, final List fullyQualifiedNames) throws InterruptedException { - if (exportMode != ScriptExportMode.AS) { - getCode().toASMSource(abc.constants, trait, abc.method_info.get(this.method_info), this, exportMode, writer); - } else { - if ((DEBUG_FIXED != null && !path.endsWith(DEBUG_FIXED)) || (!Configuration.decompile.get())) { - //writer.startMethod(this.method_info); - writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine(); - //writer.endMethod(); - return writer; - } - int timeout = Configuration.decompilationTimeoutSingleMethod.get(); - - try (Statistics s = new Statistics("MethodBody.toString")) { - if (convertException == null) { - HashMap localRegNames = getLocalRegNames(abc); - //writer.startMethod(this.method_info); - if (Configuration.showMethodBodyId.get()) { - writer.appendNoHilight("// method body index: "); - writer.appendNoHilight(abc.findBodyIndex(this.method_info)); - writer.appendNoHilight(" method index: "); - writer.appendNoHilight(this.method_info); - writer.newLine(); - } - Graph.graphToString(convertedItems, writer, LocalData.create(abc.constants, localRegNames, fullyQualifiedNames)); - //writer.endMethod(); - } else if (convertException instanceof TimeoutException) { - // exception was logged in convert method - Helper.appendTimeoutCommentAs3(writer, timeout, getCode().code.size()); - } else { - // exception was logged in convert method - Helper.appendErrorComment(writer, convertException); - } - } - } - return writer; - } - - public MethodBody convertMethodBody(ConvertData convertData, String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, Trait trait, ScopeStack scopeStack, boolean isStaticInitializer, List fullyQualifiedNames, List initTraits) throws InterruptedException { - MethodBody body = clone(); - AVM2Code code = body.getCode(); - code.fixJumps(path, body); - - if (convertData.deobfuscationMode != 0) { - try { - code.removeTraps(trait, method_info, body, abc, scriptIndex, classIndex, isStatic, path); - } catch (ThreadDeath | InterruptedException ex) { - throw ex; - } catch (Throwable ex) { - //ignore - logger.log(Level.SEVERE, "Deobfuscation failed in: " + path, ex); - body = clone(); - code = body.getCode(); - code.fixJumps(path, body); - return body; - } - } - - return body; - } - - public String toSource() { - ConvertData convertData = new ConvertData(); - convertData.deobfuscationMode = 0; - try { - convert(convertData, "", ScriptExportMode.AS, false, method_info, 0, 0, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true); - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); - writer.indent().indent().indent(); - toString("", ScriptExportMode.AS, abc, null, writer, new ArrayList<>()); - writer.unindent().unindent().unindent(); - return writer.toString(); - } catch (InterruptedException ex) { - logger.log(Level.SEVERE, null, ex); - } - - return null; - } - - @Override - public MethodBody clone() { - try { - MethodBody ret = (MethodBody) super.clone(); - if (code != null) { - ret.code = code.clone(); - } - - if (exceptions != null) { - ret.exceptions = new ABCException[exceptions.length]; - for (int i = 0; i < exceptions.length; i++) { - ret.exceptions[i] = exceptions[i].clone(); - } - } - - // maybe deep clone traits - /*if (traits != null) { - ret.traits = traits.clone(); - }*/ - ret.convertedItems = null; - ret.convertException = null; - - return ret; - } catch (CloneNotSupportedException ex) { - throw new RuntimeException(); - } - } - - public boolean autoFillStats(ABC abc, int initScope, boolean hasThis) { - //System.out.println("--------------"); - CodeStats stats = getCode().getStats(abc, this, initScope); - if (stats == null) { - return false; - } - if (stats.has_activation) { - initScope++; - } - max_stack = stats.maxstack; - max_scope_depth = stats.maxscope + (stats.has_activation ? 1 : 0); - max_regs = stats.maxlocal; - init_scope_depth = initScope; - abc.method_info.get(method_info).setFlagSetsdxns(stats.has_set_dxns); - abc.method_info.get(method_info).setFlagNeed_activation(stats.has_activation); - MethodInfo mi = abc.method_info.get(method_info); - int min_regs = mi.param_types.length + 1 + (mi.flagNeed_rest() ? 1 : 0); - if (max_regs < min_regs) { - max_regs = min_regs; - } - return true; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.abc.types; + +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.ABCInputStream; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; +import com.jpexs.decompiler.flash.abc.avm2.CodeStats; +import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCode; +import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.flash.abc.types.traits.Traits; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; +import com.jpexs.decompiler.flash.helpers.NulWriter; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.SWFField; +import com.jpexs.decompiler.graph.DottedChain; +import com.jpexs.decompiler.graph.Graph; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.ScopeStack; +import com.jpexs.decompiler.graph.model.LocalData; +import com.jpexs.helpers.CancellableWorker; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.MemoryInputStream; +import com.jpexs.helpers.stat.Statistics; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public final class MethodBody implements Cloneable { + + private static final Logger logger = Logger.getLogger(MethodBody.class.getName()); + + private static final String DEBUG_FIXED = null; + + @Internal + public boolean deleted; + + @Internal + boolean debugMode = false; + + public int method_info; + + public int max_stack; + + public int max_regs; + + public int init_scope_depth; + + public int max_scope_depth; + + @SWFField + private byte[] codeBytes; + + private AVM2Code code; + + public ABCException[] exceptions; + + public Traits traits; + + @Internal + public transient List convertedItems; + + @Internal + public transient Throwable convertException; + + @Internal + private ABC abc; + + public MethodBody() { + this.traits = new Traits(); + this.codeBytes = SWFInputStream.BYTE_ARRAY_EMPTY; + this.exceptions = new ABCException[0]; + this.abc = null; + } + + public void setAbc(ABC abc) { + this.abc = abc; + } + + public MethodBody(ABC abc, Traits traits, byte[] codeBytes, ABCException[] exceptions) { + this.traits = traits; + this.codeBytes = codeBytes; + this.exceptions = exceptions; + this.abc = abc; + } + + public synchronized void setCodeBytes(byte codeBytes[]) { + this.codeBytes = codeBytes; + this.code = null; + } + + public void setModified() { + this.codeBytes = null; + } + + public synchronized byte[] getCodeBytes() { + if (codeBytes != null) { + return codeBytes; + } else { + return code.getBytes(); + } + } + + public synchronized AVM2Code getCode() { + if (code == null) { + AVM2Code avm2Code; + try { + ABCInputStream ais = new ABCInputStream(new MemoryInputStream(codeBytes)); + avm2Code = new AVM2Code(ais, this); + avm2Code.removeWrongIndices(abc.constants); + } catch (UnknownInstructionCode | IOException ex) { + avm2Code = new AVM2Code(); + logger.log(Level.SEVERE, null, ex); + } + avm2Code.compact(); + code = avm2Code; + } + return code; + } + + public void setCode(AVM2Code code) { + this.code = code; + this.codeBytes = null; + } + + public List getExceptionEntries() { + List ret = new ArrayList<>(); + AVM2Code code = getCode(); + for (ABCException e : exceptions) { + ret.add(code.adr2pos(e.start, true)); + ret.add(code.adr2pos(e.end, true)); + ret.add(code.adr2pos(e.target)); + } + return ret; + } + + public void markOffsets() { + getCode().markOffsets(); + } + + @Override + public String toString() { + String s = ""; + s += "method_info=" + method_info + " max_stack=" + max_stack + " max_regs=" + max_regs + " scope_depth=" + init_scope_depth + " max_scope=" + max_scope_depth; + s += "\r\nCode:\r\n" + getCode().toString(); + return s; + } + + public int removeDeadCode(AVM2ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException { + return getCode().removeDeadCode(this); + } + + public int removeTraps(ABC abc, Trait trait, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException { + + return getCode().removeTraps(trait, method_info, this, abc, scriptIndex, classIndex, isStatic, path); + } + + public void deobfuscate(DeobfuscationLevel level, Trait trait, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException { + if (level == DeobfuscationLevel.LEVEL_REMOVE_DEAD_CODE) { + removeDeadCode(abc.constants, trait, abc.method_info.get(method_info)); + } else if (level == DeobfuscationLevel.LEVEL_REMOVE_TRAPS) { + removeTraps(abc, trait, scriptIndex, classIndex, isStatic, path); + } else if (level == DeobfuscationLevel.LEVEL_RESTORE_CONTROL_FLOW) { + removeTraps(abc, trait, scriptIndex, classIndex, isStatic, path); + } + + ((Tag) abc.parentTag).setModified(true); + } + + public void removeInstruction(int pos) { + getCode().removeInstruction(pos, this); + } + + /** + * Replaces instruction by another. Properly handles offsets. Note: If + * newinstruction is jump, the offset operand must be handled properly by + * caller. + * + * @param pos + * @param instruction + */ + public void replaceInstruction(int pos, AVM2Instruction instruction) { + getCode().replaceInstruction(pos, instruction, this); + } + + /** + * Inserts instruction at specified point. Handles offsets properly. Note: + * If newinstruction is jump, the offset operand must be handled properly by + * caller. All old jump offsets to pos are targeted before new instruction. + * + * @param pos Position in the list + * @param instruction Instruction False means before new instruction + */ + public void insertInstruction(int pos, AVM2Instruction instruction) { + getCode().insertInstruction(pos, instruction, this); + } + + public void insertAll(int pos, List list) { + for (AVM2Instruction ins : list) { + insertInstruction(pos++, ins); + } + } + + /** + * Inserts instruction at specified point. Handles offsets properly. Note: + * If newinstruction is jump, the offset operand must be handled properly by + * caller. + * + * @param pos Position in the list + * @param instruction Instruction + * @param mapOffsetsAfterIns Map all jumps to the pos after new instruction? + * False means before new instruction + */ + public void insertInstruction(int pos, AVM2Instruction instruction, boolean mapOffsetsAfterIns) { + getCode().insertInstruction(pos, instruction, mapOffsetsAfterIns, this); + } + + public int getLocalReservedCount() { + MethodInfo methodInfo = abc.method_info.get(this.method_info); + int pos = methodInfo.param_types.length + 1; + if (methodInfo.flagNeed_arguments()) { + pos++; + } + if (methodInfo.flagNeed_rest()) { + pos++; + } + return pos; + } + + public HashMap getLocalRegNames(ABC abc) { + HashMap ret = new HashMap<>(); + for (int i = 1; i <= abc.method_info.get(this.method_info).param_types.length; i++) { + String paramName = "param" + i; + if (abc.method_info.get(this.method_info).flagHas_paramnames() && Configuration.paramNamesEnable.get()) { + paramName = abc.constants.getString(abc.method_info.get(this.method_info).paramNames[i - 1]); + } + ret.put(i, paramName); + } + int pos = abc.method_info.get(this.method_info).param_types.length + 1; + if (abc.method_info.get(this.method_info).flagNeed_arguments()) { + ret.put(pos, "arguments"); + pos++; + } + if (abc.method_info.get(this.method_info).flagNeed_rest()) { + ret.put(pos, "rest"); + pos++; + } + + if (Configuration.getLocalNamesFromDebugInfo.get()) { + Map debugRegNames = getCode().getLocalRegNamesFromDebug(abc); + for (int k : debugRegNames.keySet()) { + ret.put(k, debugRegNames.get(k)); + } + } + return ret; + } + + public void convert(final ConvertData convertData, final String path, ScriptExportMode exportMode, final boolean isStatic, final int methodIndex, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final ScopeStack scopeStack, final int initializerType, final NulWriter writer, final List fullyQualifiedNames, final List initTraits, boolean firstLevel) throws InterruptedException { + if (debugMode) { + System.err.println("Decompiling " + path); + } + if (exportMode != ScriptExportMode.AS) { + getCode().toASMSource(abc.constants, trait, abc.method_info.get(this.method_info), this, exportMode, writer); + } else { + if ((DEBUG_FIXED != null && !path.endsWith(DEBUG_FIXED)) || (!Configuration.decompile.get())) { + writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine(); + return; + } + int timeout = Configuration.decompilationTimeoutSingleMethod.get(); + convertException = null; + try { + Callable callable = new Callable() { + @Override + public Void call() throws InterruptedException { + try (Statistics s1 = new Statistics("MethodBody.convert")) { + MethodBody converted = convertMethodBody(convertData, path, isStatic, scriptIndex, classIndex, abc, trait, scopeStack, initializerType != GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, fullyQualifiedNames, initTraits); + HashMap localRegNames = getLocalRegNames(abc); + List convertedItems1; + try (Statistics s = new Statistics("AVM2Code.toGraphTargetItems")) { + convertedItems1 = converted.getCode().toGraphTargetItems(convertData.thisHasDefaultToPrimitive, convertData, path, methodIndex, isStatic, scriptIndex, classIndex, abc, converted, localRegNames, scopeStack, initializerType, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap<>(), converted.getCode().visitCode(converted)); + } + try (Statistics s = new Statistics("Graph.graphToString")) { + Graph.graphToString(convertedItems1, writer, LocalData.create(abc.constants, localRegNames, fullyQualifiedNames)); + } + convertedItems = convertedItems1; + } + return null; + } + }; + if (firstLevel) { + CancellableWorker.call(callable, timeout, TimeUnit.SECONDS); + } else { + callable.call(); + } + } catch (InterruptedException ex) { + throw ex; + } catch (Exception | OutOfMemoryError | StackOverflowError ex) { + + convertException = ex; + Throwable cause = ex.getCause(); + if (ex instanceof ExecutionException && cause instanceof Exception) { + convertException = (Exception) cause; + } + if (convertException instanceof TimeoutException) { + logger.log(Level.SEVERE, "Decompilation timeout in: " + path, convertException); + } else { + logger.log(Level.SEVERE, "Decompilation error in: " + path, convertException); + } + + } + } + } + + public GraphTextWriter toString(final String path, ScriptExportMode exportMode, final ABC abc, final Trait trait, final GraphTextWriter writer, final List fullyQualifiedNames) throws InterruptedException { + if (exportMode != ScriptExportMode.AS) { + getCode().toASMSource(abc.constants, trait, abc.method_info.get(this.method_info), this, exportMode, writer); + } else { + if ((DEBUG_FIXED != null && !path.endsWith(DEBUG_FIXED)) || (!Configuration.decompile.get())) { + //writer.startMethod(this.method_info); + writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine(); + //writer.endMethod(); + return writer; + } + int timeout = Configuration.decompilationTimeoutSingleMethod.get(); + + try (Statistics s = new Statistics("MethodBody.toString")) { + if (convertException == null) { + HashMap localRegNames = getLocalRegNames(abc); + //writer.startMethod(this.method_info); + if (Configuration.showMethodBodyId.get()) { + writer.appendNoHilight("// method body index: "); + writer.appendNoHilight(abc.findBodyIndex(this.method_info)); + writer.appendNoHilight(" method index: "); + writer.appendNoHilight(this.method_info); + writer.newLine(); + } + Graph.graphToString(convertedItems, writer, LocalData.create(abc.constants, localRegNames, fullyQualifiedNames)); + //writer.endMethod(); + } else if (convertException instanceof TimeoutException) { + // exception was logged in convert method + Helper.appendTimeoutCommentAs3(writer, timeout, getCode().code.size()); + } else { + // exception was logged in convert method + Helper.appendErrorComment(writer, convertException); + } + } + } + return writer; + } + + public MethodBody convertMethodBody(ConvertData convertData, String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, Trait trait, ScopeStack scopeStack, boolean isStaticInitializer, List fullyQualifiedNames, List initTraits) throws InterruptedException { + MethodBody body = clone(); + AVM2Code code = body.getCode(); + code.fixJumps(path, body); + + if (convertData.deobfuscationMode != 0) { + try { + code.removeTraps(trait, method_info, body, abc, scriptIndex, classIndex, isStatic, path); + } catch (ThreadDeath | InterruptedException ex) { + throw ex; + } catch (Throwable ex) { + //ignore + logger.log(Level.SEVERE, "Deobfuscation failed in: " + path, ex); + body = clone(); + code = body.getCode(); + code.fixJumps(path, body); + return body; + } + } + + return body; + } + + public String toSource() { + ConvertData convertData = new ConvertData(); + convertData.deobfuscationMode = 0; + try { + convert(convertData, "", ScriptExportMode.AS, false, method_info, 0, 0, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true); + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); + writer.indent().indent().indent(); + toString("", ScriptExportMode.AS, abc, null, writer, new ArrayList<>()); + writer.unindent().unindent().unindent(); + return writer.toString(); + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, null, ex); + } + + return null; + } + + @Override + public MethodBody clone() { + try { + MethodBody ret = (MethodBody) super.clone(); + if (code != null) { + ret.code = code.clone(); + } + + if (exceptions != null) { + ret.exceptions = new ABCException[exceptions.length]; + for (int i = 0; i < exceptions.length; i++) { + ret.exceptions[i] = exceptions[i].clone(); + } + } + + // maybe deep clone traits + /*if (traits != null) { + ret.traits = traits.clone(); + }*/ + ret.convertedItems = null; + ret.convertException = null; + + return ret; + } catch (CloneNotSupportedException ex) { + throw new RuntimeException(); + } + } + + public boolean autoFillStats(ABC abc, int initScope, boolean hasThis) { + //System.out.println("--------------"); + CodeStats stats = getCode().getStats(abc, this, initScope); + if (stats == null) { + return false; + } + if (stats.has_activation) { + initScope++; + } + max_stack = stats.maxstack; + max_scope_depth = stats.maxscope + (stats.has_activation ? 1 : 0); + max_regs = stats.maxlocal; + init_scope_depth = initScope; + abc.method_info.get(method_info).setFlagSetsdxns(stats.has_set_dxns); + abc.method_info.get(method_info).setFlagNeed_activation(stats.has_activation); + MethodInfo mi = abc.method_info.get(method_info); + int min_regs = mi.param_types.length + 1 + (mi.flagNeed_rest() ? 1 : 0); + if (max_regs < min_regs) { + max_regs = min_regs; + } + return true; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/LocalDataArea.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/LocalDataArea.java index f2bfa8360..7b9ed41aa 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/LocalDataArea.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/LocalDataArea.java @@ -1,93 +1,93 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.action; - -import com.jpexs.decompiler.flash.ecma.EcmaScript; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Stack; - -/** - * - * @author JPEXS - */ -public class LocalDataArea { - - public List constantPool; - - public Stack stack = new Stack<>(); - - public List functions = new ArrayList<>(); - - public Map localVariables = new HashMap<>(); - - public List withs = new ArrayList<>(); - - public Map localRegisters = new HashMap<>(); - - public Object target; - - public Stage stage; - - public Long jump; - - public Object returnValue; - - public String executionException; - - public LocalDataArea(Stage stage) { - this.stage = stage; - this.target = this.stage; - } - - public LocalDataArea(Stage stage, boolean preserveVariableOrder) { - this.stage = stage; - target = this.stage; - if (preserveVariableOrder) { - localVariables = new LinkedHashMap<>(); - } - } - - public void clear() { - constantPool = null; - stack.clear(); - localVariables.clear(); - localRegisters.clear(); - withs.clear(); - functions.clear(); - stage.clear(); - jump = null; - returnValue = null; - executionException = null; - target = stage; - } - - public Object pop() { - return stack.pop(); - } - - public Double popAsNumber() { - return EcmaScript.toNumberAs2(stack.pop()); - } - - public String popAsString() { - return EcmaScript.toString(stack.pop()); - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.action; + +import com.jpexs.decompiler.flash.ecma.EcmaScript; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +/** + * + * @author JPEXS + */ +public class LocalDataArea { + + public List constantPool; + + public Stack stack = new Stack<>(); + + public List functions = new ArrayList<>(); + + public Map localVariables = new HashMap<>(); + + public List withs = new ArrayList<>(); + + public Map localRegisters = new HashMap<>(); + + public Object target; + + public Stage stage; + + public Long jump; + + public Object returnValue; + + public String executionException; + + public LocalDataArea(Stage stage) { + this.stage = stage; + this.target = this.stage; + } + + public LocalDataArea(Stage stage, boolean preserveVariableOrder) { + this.stage = stage; + target = this.stage; + if (preserveVariableOrder) { + localVariables = new LinkedHashMap<>(); + } + } + + public void clear() { + constantPool = null; + stack.clear(); + localVariables.clear(); + localRegisters.clear(); + withs.clear(); + functions.clear(); + stage.clear(); + jump = null; + returnValue = null; + executionException = null; + target = stage; + } + + public Object pop() { + return stack.pop(); + } + + public Double popAsNumber() { + return EcmaScript.toNumberAs2(stack.pop()); + } + + public String popAsString() { + return EcmaScript.toString(stack.pop()); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/special/ActionUnknown.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/special/ActionUnknown.java index 0273d1aee..1b079ceb9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/special/ActionUnknown.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/special/ActionUnknown.java @@ -1,51 +1,51 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.action.special; - -import com.jpexs.decompiler.flash.action.LocalDataArea; -import com.jpexs.decompiler.graph.GraphSourceItem; -import com.jpexs.decompiler.graph.GraphTargetItem; -import com.jpexs.decompiler.graph.TranslateStack; -import com.jpexs.helpers.Helper; -import java.util.HashMap; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class ActionUnknown extends ActionNop { - - public ActionUnknown(int actionCode, int actionLength) { - super(actionCode); - this.actionLength = actionLength; - } - - @Override - public String toString() { - return "Unknown_" + Helper.byteToHex((byte) getActionCode()); - } - - @Override - public boolean execute(LocalDataArea lda) { - return true; - } - - @Override - public void translate(GraphSourceItem lineStartItem, TranslateStack stack, List output, HashMap regNames, HashMap variables, HashMap functions, int staticOperation, String path) { - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.action.special; + +import com.jpexs.decompiler.flash.action.LocalDataArea; +import com.jpexs.decompiler.graph.GraphSourceItem; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.TranslateStack; +import com.jpexs.helpers.Helper; +import java.util.HashMap; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class ActionUnknown extends ActionNop { + + public ActionUnknown(int actionCode, int actionLength) { + super(actionCode); + this.actionLength = actionLength; + } + + @Override + public String toString() { + return "Unknown_" + Helper.byteToHex((byte) getActionCode()); + } + + @Override + public boolean execute(LocalDataArea lda) { + return true; + } + + @Override + public void translate(GraphSourceItem lineStartItem, TranslateStack stack, List output, HashMap regNames, HashMap variables, HashMap functions, int staticOperation, String path) { + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java index c23795331..0ead00e93 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java @@ -1,455 +1,455 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.action.swf4; - -import com.jpexs.decompiler.flash.BaseLocalData; -import com.jpexs.decompiler.flash.EndOfStreamException; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.action.Action; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.action.LocalDataArea; -import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; -import com.jpexs.decompiler.flash.action.model.TemporaryRegister; -import com.jpexs.decompiler.flash.action.parser.ActionParseException; -import com.jpexs.decompiler.flash.action.parser.pcode.ASMParsedSymbol; -import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.dumpview.DumpInfo; -import com.jpexs.decompiler.flash.ecma.Null; -import com.jpexs.decompiler.flash.ecma.Undefined; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; -import com.jpexs.decompiler.flash.types.annotations.SWFVersion; -import com.jpexs.decompiler.graph.GraphSourceItem; -import com.jpexs.decompiler.graph.GraphTargetItem; -import com.jpexs.decompiler.graph.TranslateStack; -import com.jpexs.decompiler.graph.model.FalseItem; -import com.jpexs.decompiler.graph.model.TrueItem; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Set; - -/** - * - * @author JPEXS - */ -@SWFVersion(from = 4) -public class ActionPush extends Action { - - public List values; - - public List replacement; - - public List constantPool; - - public ActionPush(int actionLength, SWFInputStream sis, int version) throws IOException { - super(0x96, actionLength); - int type; - values = new ArrayList<>(); - DumpInfo di = sis.dumpInfo; - sis = sis.getLimitedStream(actionLength); - sis.dumpInfo = di; - try { - while (sis.available() > 0) { - type = sis.readUI8("type"); - switch (type) { - case 0: - values.add(sis.readString("string")); - break; - case 1: - values.add(sis.readFLOAT("float")); - break; - case 2: - values.add(Null.INSTANCE); - break; - case 3: - values.add(Undefined.INSTANCE); - break; - case 4: - values.add(new RegisterNumber(sis.readUI8("registerNumber"))); - break; - case 5: - int b = sis.readUI8("boolean"); - if (b == 0) { - values.add((Boolean) false); - } else { - values.add((Boolean) true); - } - - break; - case 6: - values.add(sis.readDOUBLE("double")); - break; - case 7: - long el = sis.readSI32("integer"); - values.add((Long) el); - break; - case 8: - values.add(new ConstantIndex(sis.readUI8("constantIndex"))); - break; - case 9: - values.add(new ConstantIndex(sis.readUI16("constantIndex"))); - break; - } - } - } catch (EndOfStreamException ex) { - } - } - - @Override - protected void getContentBytes(SWFOutputStream sos) throws IOException { - for (Object o : values) { - if (o instanceof String) { - sos.writeUI8(0); - sos.writeString((String) o); - } else if (o instanceof Float) { - sos.writeUI8(1); - sos.writeFLOAT((Float) o); - } else if (o == Null.INSTANCE) { - sos.writeUI8(2); - } else if (o == Undefined.INSTANCE) { - sos.writeUI8(3); - } else if (o instanceof RegisterNumber) { - sos.writeUI8(4); - sos.writeUI8(((RegisterNumber) o).number); - } else if (o instanceof Boolean) { - sos.writeUI8(5); - sos.writeUI8((Boolean) o ? 1 : 0); - } else if (o instanceof Number) { - if (o instanceof Long) { - long l = (Long) o; - if (l < -0x80000000 || l > 0x7fffffff) { - o = (double) l; - } - } - if (o instanceof Double || o instanceof Float) { - sos.writeUI8(6); - sos.writeDOUBLE(((Number) o).doubleValue()); - } else if (o instanceof Long || o instanceof Integer || o instanceof Short || o instanceof Byte) { - sos.writeUI8(7); - sos.writeSI32(((Number) o).longValue()); - } - } else if (o instanceof ConstantIndex) { - int cIndex = ((ConstantIndex) o).index; - if (cIndex < 256) { - sos.writeUI8(8); - sos.writeUI8(cIndex); - } else { - sos.writeUI8(9); - sos.writeUI16(cIndex); - } - } - } - } - - /** - * Gets the length of action converted to bytes - * - * @return Length - */ - @Override - protected int getContentBytesLength() { - int res = 0; - for (Object o : values) { - if (o instanceof String) { - res += Utf8Helper.getBytesLength((String) o) + 2; - } else if (o instanceof Float) { - res += 5; - } else if (o == Null.INSTANCE) { - res++; - } else if (o == Undefined.INSTANCE) { - res++; - } else if (o instanceof RegisterNumber) { - res += 2; - } else if (o instanceof Boolean) { - res += 2; - } else if (o instanceof Number) { - if (o instanceof Long) { - long l = (Long) o; - if (l < -0x80000000 || l > 0x7fffffff) { - o = (double) l; - } - } - if (o instanceof Double || o instanceof Float) { - res += 9; - } else if (o instanceof Long || o instanceof Integer || o instanceof Short || o instanceof Byte) { - res += 5; - } - } else if (o instanceof ConstantIndex) { - int cIndex = ((ConstantIndex) o).index; - if (cIndex < 256) { - res += 2; - } else { - res += 3; - } - } - } - - return res; - } - - public static boolean isValidValue(Object value) { - if (value instanceof String) { - for (char ch : ((String) value).toCharArray()) { - if (ch == 0) { - return false; - } - } - } - if (value instanceof Long) { - long l = (Long) value; - if (l < -0x80000000 || l > 0x7fffffff) { - return false; - } - } - return true; - } - - public ActionPush(Object value) { - super(0x96, 0); - this.values = new ArrayList<>(); - this.values.add(value); - updateLength(); - } - - public ActionPush(Object[] values) { - super(0x96, 0); - this.values = new ArrayList<>(); - this.values.addAll(Arrays.asList(values)); - updateLength(); - } - - public ActionPush(FlasmLexer lexer, List constantPool) throws IOException, ActionParseException { - super(0x96, 0); - this.constantPool = constantPool; - values = new ArrayList<>(); - int count = 0; - loop: - while (true) { - ASMParsedSymbol symb = lexer.yylex(); - switch (symb.type) { - case ASMParsedSymbol.TYPE_STRING: - count++; - if (constantPool.contains((String) symb.value)) { - values.add(new ConstantIndex(constantPool.indexOf(symb.value))); - } else { - values.add(symb.value); - } - break; - case ASMParsedSymbol.TYPE_FLOAT: - case ASMParsedSymbol.TYPE_NULL: - case ASMParsedSymbol.TYPE_UNDEFINED: - case ASMParsedSymbol.TYPE_REGISTER: - case ASMParsedSymbol.TYPE_BOOLEAN: - case ASMParsedSymbol.TYPE_INTEGER: - case ASMParsedSymbol.TYPE_CONSTANT: - count++; - values.add(symb.value); - break; - case ASMParsedSymbol.TYPE_EOL: - case ASMParsedSymbol.TYPE_EOF: - if (count == 0) { - throw new ActionParseException("Arguments expected", lexer.yyline()); - } else { - break loop; - } - case ASMParsedSymbol.TYPE_COMMENT: - break; - default: - throw new ActionParseException("Arguments expected, " + symb.type + " " + symb.value + " found", lexer.yyline()); - } - } - } - - @Override - public GraphTextWriter getASMSourceReplaced(ActionList container, Set knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) { - if (replacement == null || replacement.size() < values.size()) { - return toString(writer); - } - List oldVal = values; - values = replacement; - toString(writer); - values = oldVal; - return writer; - } - - public GraphTextWriter paramsToStringReplaced(List container, Set knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) { - if (replacement == null || replacement.size() < values.size()) { - return paramsToString(writer); - } - List oldVal = values; - values = replacement; - paramsToString(writer); - values = oldVal; - return writer; - } - - public String toStringNoQ(int i) { - String ret; - Object value = values.get(i); - if (value instanceof ConstantIndex) { - ret = ((ConstantIndex) value).toStringNoQ(constantPool, Configuration.resolveConstants.get()); - } else if (value instanceof String) { - ret = (String) value; - } else if (value instanceof RegisterNumber) { - ret = ((RegisterNumber) value).toStringNoName(); - } else { - ret = value.toString(); - } - return ret; - } - - public String toString(int i) { - String ret; - Object value = values.get(i); - if (value instanceof ConstantIndex) { - ret = ((ConstantIndex) value).toString(constantPool, Configuration.resolveConstants.get()); - } else if (value instanceof String) { - ret = "\"" + Helper.escapeActionScriptString((String) value) + "\""; - } else if (value instanceof RegisterNumber) { - ret = ((RegisterNumber) value).toStringNoName(); - } else { - ret = value.toString(); - } - return ret; - } - - public GraphTextWriter paramsToString(GraphTextWriter writer) { - int pos = 0; - for (int i = 0; i < values.size(); i++) { - if (pos > 0) { - writer.appendNoHilight(" "); - } - writer.append(toString(i), getAddress() + pos + 1, getFileOffset()); - pos++; - } - return writer; - } - - @Override - public String toString() { - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); - toString(writer); - return writer.toString(); - } - - public GraphTextWriter toString(GraphTextWriter writer) { - writer.appendNoHilight("Push "); - paramsToString(writer); - return writer; - } - - @Override - public boolean execute(LocalDataArea lda) { - for (Object value : values) { - if (value instanceof ConstantIndex) { - ConstantIndex constantIndex = (ConstantIndex) value; - List cPool = lda.constantPool != null ? lda.constantPool : constantPool; - lda.stack.push(constantIndex.toStringNoQ(cPool, true)); - } else if (value instanceof RegisterNumber) { - int rn = ((RegisterNumber) value).number; - if (lda.localRegisters.containsKey(rn)) { - lda.stack.push(lda.localRegisters.get(rn)); - } else { - lda.stack.push(Undefined.INSTANCE); - } - } else { - lda.stack.push(value); - } - } - - return true; - } - - @Override - public void translate(GraphSourceItem lineStartAction, TranslateStack stack, List output, HashMap regNames, HashMap variables, HashMap functions, int staticOperation, String path) { - int pos = 0; - for (Object o : values) { - if (o instanceof ConstantIndex) { - if ((constantPool == null) || (((ConstantIndex) o).index >= constantPool.size())) { - o = "\u00A7\u00A7constant" + ((ConstantIndex) o).index; - } else { - o = constantPool.get(((ConstantIndex) o).index); - } - } - /*if (o instanceof RegisterNumber) { - if (regNames.containsKey(((RegisterNumber) o).number)) { - ((RegisterNumber) o).name = regNames.get(((RegisterNumber) o).number); - } else if (output.size() >= 2) { //chained assignments:, ignore for class prototype assignment - GraphTargetItem last = output.get(output.size() - 1); - GraphTargetItem prev = output.get(output.size() - 2); - if (last instanceof SetTypeActionItem) { - if (prev instanceof StoreRegisterActionItem) { - StoreRegisterActionItem str = (StoreRegisterActionItem) prev; - if (str.register.number == ((RegisterNumber) o).number) { - SetTypeActionItem stt = (SetTypeActionItem) last; - stt.setTempRegister(((RegisterNumber) o).number); - if ((stt.getValue() instanceof IncrementActionItem) && (((IncrementActionItem) stt.getValue()).object.equals(stt.getObject()))) { - stack.push(new PreIncrementActionItem(this, lineStartAction, stt.getObject())); - } else if ((stt.getValue() instanceof DecrementActionItem) && (((DecrementActionItem) stt.getValue()).object.equals(stt.getObject()))) { - stack.push(new PreDecrementActionItem(this, lineStartAction, stt.getObject())); - } else { - //stack.push(last); - continue; - } - output.remove(output.size() - 1); - output.remove(output.size() - 1); - pos++; - continue; - } - } - } - } - }*/ - if (o instanceof Boolean) { - Boolean b = (Boolean) o; - if (b) { - stack.push(new TrueItem(this, lineStartAction)); - } else { - stack.push(new FalseItem(this, lineStartAction)); - } - } else { - DirectValueActionItem dvt = new DirectValueActionItem(this, lineStartAction, pos, o, constantPool); - - if (o instanceof RegisterNumber) {//TemporaryRegister - dvt.computedRegValue = variables.get("__register" + ((RegisterNumber) o).number); - if (regNames.containsKey(((RegisterNumber) o).number)) { - ((RegisterNumber) o).name = regNames.get(((RegisterNumber) o).number); - } - } - if (dvt.computedRegValue instanceof TemporaryRegister) { - stack.push(new TemporaryRegister(((RegisterNumber) o).number, ((TemporaryRegister) dvt.computedRegValue).value)); - } else { - stack.push(dvt); - } - } - pos++; - } - } - - @Override - public int getStackPushCount(BaseLocalData localData, TranslateStack stack) { - return values.size(); - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.action.swf4; + +import com.jpexs.decompiler.flash.BaseLocalData; +import com.jpexs.decompiler.flash.EndOfStreamException; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.LocalDataArea; +import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; +import com.jpexs.decompiler.flash.action.model.TemporaryRegister; +import com.jpexs.decompiler.flash.action.parser.ActionParseException; +import com.jpexs.decompiler.flash.action.parser.pcode.ASMParsedSymbol; +import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.dumpview.DumpInfo; +import com.jpexs.decompiler.flash.ecma.Null; +import com.jpexs.decompiler.flash.ecma.Undefined; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; +import com.jpexs.decompiler.flash.types.annotations.SWFVersion; +import com.jpexs.decompiler.graph.GraphSourceItem; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.TranslateStack; +import com.jpexs.decompiler.graph.model.FalseItem; +import com.jpexs.decompiler.graph.model.TrueItem; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +/** + * + * @author JPEXS + */ +@SWFVersion(from = 4) +public class ActionPush extends Action { + + public List values; + + public List replacement; + + public List constantPool; + + public ActionPush(int actionLength, SWFInputStream sis, int version) throws IOException { + super(0x96, actionLength); + int type; + values = new ArrayList<>(); + DumpInfo di = sis.dumpInfo; + sis = sis.getLimitedStream(actionLength); + sis.dumpInfo = di; + try { + while (sis.available() > 0) { + type = sis.readUI8("type"); + switch (type) { + case 0: + values.add(sis.readString("string")); + break; + case 1: + values.add(sis.readFLOAT("float")); + break; + case 2: + values.add(Null.INSTANCE); + break; + case 3: + values.add(Undefined.INSTANCE); + break; + case 4: + values.add(new RegisterNumber(sis.readUI8("registerNumber"))); + break; + case 5: + int b = sis.readUI8("boolean"); + if (b == 0) { + values.add((Boolean) false); + } else { + values.add((Boolean) true); + } + + break; + case 6: + values.add(sis.readDOUBLE("double")); + break; + case 7: + long el = sis.readSI32("integer"); + values.add((Long) el); + break; + case 8: + values.add(new ConstantIndex(sis.readUI8("constantIndex"))); + break; + case 9: + values.add(new ConstantIndex(sis.readUI16("constantIndex"))); + break; + } + } + } catch (EndOfStreamException ex) { + } + } + + @Override + protected void getContentBytes(SWFOutputStream sos) throws IOException { + for (Object o : values) { + if (o instanceof String) { + sos.writeUI8(0); + sos.writeString((String) o); + } else if (o instanceof Float) { + sos.writeUI8(1); + sos.writeFLOAT((Float) o); + } else if (o == Null.INSTANCE) { + sos.writeUI8(2); + } else if (o == Undefined.INSTANCE) { + sos.writeUI8(3); + } else if (o instanceof RegisterNumber) { + sos.writeUI8(4); + sos.writeUI8(((RegisterNumber) o).number); + } else if (o instanceof Boolean) { + sos.writeUI8(5); + sos.writeUI8((Boolean) o ? 1 : 0); + } else if (o instanceof Number) { + if (o instanceof Long) { + long l = (Long) o; + if (l < -0x80000000 || l > 0x7fffffff) { + o = (double) l; + } + } + if (o instanceof Double || o instanceof Float) { + sos.writeUI8(6); + sos.writeDOUBLE(((Number) o).doubleValue()); + } else if (o instanceof Long || o instanceof Integer || o instanceof Short || o instanceof Byte) { + sos.writeUI8(7); + sos.writeSI32(((Number) o).longValue()); + } + } else if (o instanceof ConstantIndex) { + int cIndex = ((ConstantIndex) o).index; + if (cIndex < 256) { + sos.writeUI8(8); + sos.writeUI8(cIndex); + } else { + sos.writeUI8(9); + sos.writeUI16(cIndex); + } + } + } + } + + /** + * Gets the length of action converted to bytes + * + * @return Length + */ + @Override + protected int getContentBytesLength() { + int res = 0; + for (Object o : values) { + if (o instanceof String) { + res += Utf8Helper.getBytesLength((String) o) + 2; + } else if (o instanceof Float) { + res += 5; + } else if (o == Null.INSTANCE) { + res++; + } else if (o == Undefined.INSTANCE) { + res++; + } else if (o instanceof RegisterNumber) { + res += 2; + } else if (o instanceof Boolean) { + res += 2; + } else if (o instanceof Number) { + if (o instanceof Long) { + long l = (Long) o; + if (l < -0x80000000 || l > 0x7fffffff) { + o = (double) l; + } + } + if (o instanceof Double || o instanceof Float) { + res += 9; + } else if (o instanceof Long || o instanceof Integer || o instanceof Short || o instanceof Byte) { + res += 5; + } + } else if (o instanceof ConstantIndex) { + int cIndex = ((ConstantIndex) o).index; + if (cIndex < 256) { + res += 2; + } else { + res += 3; + } + } + } + + return res; + } + + public static boolean isValidValue(Object value) { + if (value instanceof String) { + for (char ch : ((String) value).toCharArray()) { + if (ch == 0) { + return false; + } + } + } + if (value instanceof Long) { + long l = (Long) value; + if (l < -0x80000000 || l > 0x7fffffff) { + return false; + } + } + return true; + } + + public ActionPush(Object value) { + super(0x96, 0); + this.values = new ArrayList<>(); + this.values.add(value); + updateLength(); + } + + public ActionPush(Object[] values) { + super(0x96, 0); + this.values = new ArrayList<>(); + this.values.addAll(Arrays.asList(values)); + updateLength(); + } + + public ActionPush(FlasmLexer lexer, List constantPool) throws IOException, ActionParseException { + super(0x96, 0); + this.constantPool = constantPool; + values = new ArrayList<>(); + int count = 0; + loop: + while (true) { + ASMParsedSymbol symb = lexer.yylex(); + switch (symb.type) { + case ASMParsedSymbol.TYPE_STRING: + count++; + if (constantPool.contains((String) symb.value)) { + values.add(new ConstantIndex(constantPool.indexOf(symb.value))); + } else { + values.add(symb.value); + } + break; + case ASMParsedSymbol.TYPE_FLOAT: + case ASMParsedSymbol.TYPE_NULL: + case ASMParsedSymbol.TYPE_UNDEFINED: + case ASMParsedSymbol.TYPE_REGISTER: + case ASMParsedSymbol.TYPE_BOOLEAN: + case ASMParsedSymbol.TYPE_INTEGER: + case ASMParsedSymbol.TYPE_CONSTANT: + count++; + values.add(symb.value); + break; + case ASMParsedSymbol.TYPE_EOL: + case ASMParsedSymbol.TYPE_EOF: + if (count == 0) { + throw new ActionParseException("Arguments expected", lexer.yyline()); + } else { + break loop; + } + case ASMParsedSymbol.TYPE_COMMENT: + break; + default: + throw new ActionParseException("Arguments expected, " + symb.type + " " + symb.value + " found", lexer.yyline()); + } + } + } + + @Override + public GraphTextWriter getASMSourceReplaced(ActionList container, Set knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) { + if (replacement == null || replacement.size() < values.size()) { + return toString(writer); + } + List oldVal = values; + values = replacement; + toString(writer); + values = oldVal; + return writer; + } + + public GraphTextWriter paramsToStringReplaced(List container, Set knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) { + if (replacement == null || replacement.size() < values.size()) { + return paramsToString(writer); + } + List oldVal = values; + values = replacement; + paramsToString(writer); + values = oldVal; + return writer; + } + + public String toStringNoQ(int i) { + String ret; + Object value = values.get(i); + if (value instanceof ConstantIndex) { + ret = ((ConstantIndex) value).toStringNoQ(constantPool, Configuration.resolveConstants.get()); + } else if (value instanceof String) { + ret = (String) value; + } else if (value instanceof RegisterNumber) { + ret = ((RegisterNumber) value).toStringNoName(); + } else { + ret = value.toString(); + } + return ret; + } + + public String toString(int i) { + String ret; + Object value = values.get(i); + if (value instanceof ConstantIndex) { + ret = ((ConstantIndex) value).toString(constantPool, Configuration.resolveConstants.get()); + } else if (value instanceof String) { + ret = "\"" + Helper.escapeActionScriptString((String) value) + "\""; + } else if (value instanceof RegisterNumber) { + ret = ((RegisterNumber) value).toStringNoName(); + } else { + ret = value.toString(); + } + return ret; + } + + public GraphTextWriter paramsToString(GraphTextWriter writer) { + int pos = 0; + for (int i = 0; i < values.size(); i++) { + if (pos > 0) { + writer.appendNoHilight(" "); + } + writer.append(toString(i), getAddress() + pos + 1, getFileOffset()); + pos++; + } + return writer; + } + + @Override + public String toString() { + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); + toString(writer); + return writer.toString(); + } + + public GraphTextWriter toString(GraphTextWriter writer) { + writer.appendNoHilight("Push "); + paramsToString(writer); + return writer; + } + + @Override + public boolean execute(LocalDataArea lda) { + for (Object value : values) { + if (value instanceof ConstantIndex) { + ConstantIndex constantIndex = (ConstantIndex) value; + List cPool = lda.constantPool != null ? lda.constantPool : constantPool; + lda.stack.push(constantIndex.toStringNoQ(cPool, true)); + } else if (value instanceof RegisterNumber) { + int rn = ((RegisterNumber) value).number; + if (lda.localRegisters.containsKey(rn)) { + lda.stack.push(lda.localRegisters.get(rn)); + } else { + lda.stack.push(Undefined.INSTANCE); + } + } else { + lda.stack.push(value); + } + } + + return true; + } + + @Override + public void translate(GraphSourceItem lineStartAction, TranslateStack stack, List output, HashMap regNames, HashMap variables, HashMap functions, int staticOperation, String path) { + int pos = 0; + for (Object o : values) { + if (o instanceof ConstantIndex) { + if ((constantPool == null) || (((ConstantIndex) o).index >= constantPool.size())) { + o = "\u00A7\u00A7constant" + ((ConstantIndex) o).index; + } else { + o = constantPool.get(((ConstantIndex) o).index); + } + } + /*if (o instanceof RegisterNumber) { + if (regNames.containsKey(((RegisterNumber) o).number)) { + ((RegisterNumber) o).name = regNames.get(((RegisterNumber) o).number); + } else if (output.size() >= 2) { //chained assignments:, ignore for class prototype assignment + GraphTargetItem last = output.get(output.size() - 1); + GraphTargetItem prev = output.get(output.size() - 2); + if (last instanceof SetTypeActionItem) { + if (prev instanceof StoreRegisterActionItem) { + StoreRegisterActionItem str = (StoreRegisterActionItem) prev; + if (str.register.number == ((RegisterNumber) o).number) { + SetTypeActionItem stt = (SetTypeActionItem) last; + stt.setTempRegister(((RegisterNumber) o).number); + if ((stt.getValue() instanceof IncrementActionItem) && (((IncrementActionItem) stt.getValue()).object.equals(stt.getObject()))) { + stack.push(new PreIncrementActionItem(this, lineStartAction, stt.getObject())); + } else if ((stt.getValue() instanceof DecrementActionItem) && (((DecrementActionItem) stt.getValue()).object.equals(stt.getObject()))) { + stack.push(new PreDecrementActionItem(this, lineStartAction, stt.getObject())); + } else { + //stack.push(last); + continue; + } + output.remove(output.size() - 1); + output.remove(output.size() - 1); + pos++; + continue; + } + } + } + } + }*/ + if (o instanceof Boolean) { + Boolean b = (Boolean) o; + if (b) { + stack.push(new TrueItem(this, lineStartAction)); + } else { + stack.push(new FalseItem(this, lineStartAction)); + } + } else { + DirectValueActionItem dvt = new DirectValueActionItem(this, lineStartAction, pos, o, constantPool); + + if (o instanceof RegisterNumber) {//TemporaryRegister + dvt.computedRegValue = variables.get("__register" + ((RegisterNumber) o).number); + if (regNames.containsKey(((RegisterNumber) o).number)) { + ((RegisterNumber) o).name = regNames.get(((RegisterNumber) o).number); + } + } + if (dvt.computedRegValue instanceof TemporaryRegister) { + stack.push(new TemporaryRegister(((RegisterNumber) o).number, ((TemporaryRegister) dvt.computedRegValue).value)); + } else { + stack.push(dvt); + } + } + pos++; + } + } + + @Override + public int getStackPushCount(BaseLocalData localData, TranslateStack stack) { + return values.size(); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/SwfSpecificConfiguration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/SwfSpecificConfiguration.java index 22963d29e..9b04c3c80 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/SwfSpecificConfiguration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/SwfSpecificConfiguration.java @@ -1,32 +1,32 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.configuration; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -/** - * - * @author JPEXS - */ -public class SwfSpecificConfiguration implements Serializable { - - public Map fontPairingMap = new HashMap<>(); - - public String lastSelectedPath = null; -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.configuration; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author JPEXS + */ +public class SwfSpecificConfiguration implements Serializable { + + public Map fontPairingMap = new HashMap<>(); + + public String lastSelectedPath = null; +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/commonshape/Matrix.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/commonshape/Matrix.java index bef21beee..0a203b52a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/commonshape/Matrix.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/commonshape/Matrix.java @@ -1,433 +1,433 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.exporters.commonshape; - -import com.jpexs.decompiler.flash.types.MATRIX; -import java.awt.geom.AffineTransform; - -/** - * - * @author JPEXS - */ -public final class Matrix implements Cloneable { - - public double scaleX = 1; - - public double scaleY = 1; - - public double rotateSkew0; - - public double rotateSkew1; - - public double translateX; - - public double translateY; - - public static Matrix getScaleInstance(double scale) { - Matrix mat = new Matrix(); - mat.scale(scale); - return mat; - } - - public static Matrix getTranslateInstance(double x, double y) { - Matrix mat = new Matrix(); - mat.translate(x, y); - return mat; - } - - public Matrix() { - scaleX = 1; - scaleY = 1; - } - - public Matrix(MATRIX matrix) { - if (matrix == null) { - matrix = new MATRIX(); - } - translateX = matrix.translateX; - translateY = matrix.translateY; - if (matrix.hasScale) { - scaleX = matrix.getScaleXFloat(); - scaleY = matrix.getScaleYFloat(); - } else { - scaleX = 1; - scaleY = 1; - } - if (matrix.hasRotate) { - rotateSkew0 = matrix.getRotateSkew0Float(); - rotateSkew1 = matrix.getRotateSkew1Float(); - } - } - - public Matrix(AffineTransform transform) { - this(); - if (transform != null) { - scaleX = transform.getScaleX(); - rotateSkew1 = transform.getShearX(); - translateX = transform.getTranslateX(); - rotateSkew0 = transform.getShearY(); - scaleY = transform.getScaleY(); - translateY = transform.getTranslateY(); - } - } - - @Override - public Matrix clone() { - try { - Matrix mat = (Matrix) super.clone(); - return mat; - } catch (CloneNotSupportedException ex) { - throw new RuntimeException(); - } - } - - public Point transform(double x, double y) { - Point result = new Point( - scaleX * x + rotateSkew1 * y + translateX, - rotateSkew0 * x + scaleY * y + translateY); - return result; - } - - public Point transform(Point point) { - return transform(point.x, point.y); - } - - public Point deltaTransform(double x, double y) { - Point result = new Point( - scaleX * x + rotateSkew1 * y, - rotateSkew0 * x + scaleY * y); - return result; - } - - public Point deltaTransform(Point point) { - return deltaTransform(point.x, point.y); - } - - public java.awt.Point deltaTransform(java.awt.Point point) { - Point p = deltaTransform(point.x, point.y); - return new java.awt.Point((int) p.x, (int) p.y); - } - - public java.awt.Point transform(java.awt.Point point) { - Point p = transform(point.x, point.y); - return new java.awt.Point((int) p.x, (int) p.y); - } - - public ExportRectangle transform(ExportRectangle rect) { - double minX = Double.MAX_VALUE; - double minY = Double.MAX_VALUE; - double maxX = Double.MIN_VALUE; - double maxY = Double.MIN_VALUE; - Point point; - point = transform(rect.xMin, rect.yMin); - if (point.x < minX) { - minX = point.x; - } - if (point.x > maxX) { - maxX = point.x; - } - if (point.y < minY) { - minY = point.y; - } - if (point.y > maxY) { - maxY = point.y; - } - point = transform(rect.xMax, rect.yMin); - if (point.x < minX) { - minX = point.x; - } - if (point.x > maxX) { - maxX = point.x; - } - if (point.y < minY) { - minY = point.y; - } - if (point.y > maxY) { - maxY = point.y; - } - point = transform(rect.xMin, rect.yMax); - if (point.x < minX) { - minX = point.x; - } - if (point.x > maxX) { - maxX = point.x; - } - if (point.y < minY) { - minY = point.y; - } - if (point.y > maxY) { - maxY = point.y; - } - point = transform(rect.xMax, rect.yMax); - if (point.x < minX) { - minX = point.x; - } - if (point.x > maxX) { - maxX = point.x; - } - if (point.y < minY) { - minY = point.y; - } - if (point.y > maxY) { - maxY = point.y; - } - return new ExportRectangle(minX, minY, maxX, maxY); - } - - public void translate(double x, double y) { - translateX = scaleX * x + rotateSkew1 * y + translateX; - translateY = rotateSkew0 * x + scaleY * y + translateY; - } - - public void scale(double factor) { - scaleX *= factor; - scaleY *= factor; - rotateSkew0 *= factor; - rotateSkew1 *= factor; - } - - public Matrix concatenate(Matrix m) { - Matrix result = new Matrix(); - result.scaleX = scaleX * m.scaleX + rotateSkew1 * m.rotateSkew0; - result.rotateSkew0 = rotateSkew0 * m.scaleX + scaleY * m.rotateSkew0; - result.rotateSkew1 = scaleX * m.rotateSkew1 + rotateSkew1 * m.scaleY; - result.scaleY = rotateSkew0 * m.rotateSkew1 + scaleY * m.scaleY; - result.translateX = scaleX * m.translateX + rotateSkew1 * m.translateY + translateX; - result.translateY = rotateSkew0 * m.translateX + scaleY * m.translateY + translateY; - return result; - } - - public Matrix preConcatenate(Matrix m) { - Matrix result = new Matrix(); - result.scaleX = m.scaleX * scaleX + m.rotateSkew1 * rotateSkew0; - result.rotateSkew0 = m.rotateSkew0 * scaleX + m.scaleY * rotateSkew0; - result.rotateSkew1 = m.scaleX * rotateSkew1 + m.rotateSkew1 * scaleY; - result.scaleY = m.rotateSkew0 * rotateSkew1 + m.scaleY * scaleY; - result.translateX = m.scaleX * translateX + m.rotateSkew1 * translateY + m.translateX; - result.translateY = m.rotateSkew0 * translateX + m.scaleY * translateY + m.translateY; - return result; - } - - public AffineTransform toTransform() { - AffineTransform transform = new AffineTransform(scaleX, rotateSkew0, - rotateSkew1, scaleY, - translateX, translateY); - return transform; - } - - public String getSvgTransformationString(double translateDivisor, double unitDivisor) { - double translateX = roundPixels400(this.translateX / translateDivisor); - double translateY = roundPixels400(this.translateY / translateDivisor); - double rotateSkew0 = roundPixels400(this.rotateSkew0 / unitDivisor); - double rotateSkew1 = roundPixels400(this.rotateSkew1 / unitDivisor); - double scaleX = roundPixels400(this.scaleX / unitDivisor); - double scaleY = roundPixels400(this.scaleY / unitDivisor); - return "matrix(" + scaleX + ", " + rotateSkew0 + ", " - + rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")"; - } - - public static String[] parseSvgNumberList(String params) { - while (params.contains(" ")) { - params = params.replaceAll(" ", " "); - } - - params = params.trim(); - params = params.replace(", ", ","); - params = params.replace(" ", ","); - String[] args = params.split(","); - return args; - } - - public static Matrix parseSvgMatrix(String transformStr, double translateDivisor, double unitDivisor) { - Matrix ret = new Matrix(); - while (transformStr != null && transformStr.length() > 0) { - String funcName = transformStr.split("\\(")[0]; - transformStr = transformStr.substring(funcName.length() + 1); - String params = transformStr.split("\\)")[0]; - transformStr = transformStr.substring(params.length() + 1).trim(); - String[] args = parseSvgNumberList(params); - funcName = funcName.trim(); - switch (funcName) { - case "matrix": - if (args.length == 6) { - double scaleX = Double.parseDouble(args[0].trim()); - double rotateSkew0 = Double.parseDouble(args[1].trim()); - double rotateSkew1 = Double.parseDouble(args[2].trim()); - double scaleY = Double.parseDouble(args[3].trim()); - double translateX = Double.parseDouble(args[4].trim()); - double translateY = Double.parseDouble(args[5].trim()); - Matrix result = new Matrix(); - result.translateX = translateX; - result.translateY = translateY; - result.rotateSkew0 = rotateSkew0; - result.rotateSkew1 = rotateSkew1; - result.scaleX = scaleX; - result.scaleY = scaleY; - ret = ret.concatenate(result); - } - break; - case "translate": - if (args.length == 1 || args.length == 2) { - double translateX = Double.parseDouble(args[0].trim()); - double translateY = 0; - if (args.length == 2) { - translateY = Double.parseDouble(args[1].trim()); - } - - Matrix result = new Matrix(); - result.translateX = translateX; - result.translateY = translateY; - ret = ret.concatenate(result); - } - break; - case "scale": - if (args.length == 1 || args.length == 2) { - double scaleX = Double.parseDouble(args[0].trim()); - double scaleY = scaleX; - if (args.length == 2) { - scaleY = Double.parseDouble(args[1].trim()); - } - - Matrix result = new Matrix(); - result.scaleX = scaleX; - result.scaleY = scaleY; - ret = ret.concatenate(result); - } - break; - case "skewX": - if (args.length == 1) { - double angle = Double.parseDouble(args[0].trim()) * Math.PI / 180; - - Matrix result = new Matrix(); - result.rotateSkew1 = Math.tan(angle); - ret = ret.concatenate(result); - } - break; - case "skewY": - if (args.length == 1) { - double angle = Double.parseDouble(args[0].trim()) * Math.PI / 180; - - Matrix result = new Matrix(); - result.rotateSkew0 = Math.tan(angle); - ret = ret.concatenate(result); - } - break; - case "rotate": - if (args.length == 1 || args.length == 3) { - double rotateAngle = Double.parseDouble(args[0].trim()); - double tx = 0; - double ty = 0; - if (args.length > 1) { - tx = Double.parseDouble(args[1].trim()); - ty = Double.parseDouble(args[2].trim()); - } - - double angleRad = -rotateAngle * Math.PI / 180; - Matrix result = new Matrix(); - result.rotateSkew0 = -Math.sin(angleRad); - result.rotateSkew1 = Math.sin(angleRad); - result.scaleX = Math.cos(angleRad); - result.scaleY = Math.cos(angleRad); - result = result.preConcatenate(getTranslateInstance(tx, ty)) - .concatenate(getTranslateInstance(-tx, -ty)); - ret = ret.concatenate(result); - } - break; - } - } - - ret.translateX *= translateDivisor; - ret.translateY *= translateDivisor; - ret.rotateSkew0 *= unitDivisor; - ret.rotateSkew1 *= unitDivisor; - ret.scaleX *= unitDivisor; - ret.scaleY *= unitDivisor; - return ret; - } - - private double roundPixels400(double pixels) { - return Math.round(pixels * 10000) / 10000.0; - } - - @Override - public String toString() { - return "[Matrix scale:" + scaleX + "," + scaleY + ", rotate:" + rotateSkew0 + "," + rotateSkew1 + ", translate:" + translateX + "," + translateY + "]"; - } - - public Matrix inverse() { - double a = scaleX; - double b = rotateSkew1; - double tx = translateX; - double c = rotateSkew0; - double d = scaleY; - double ty = translateY; - - double det = a * d - b * c; - - double a2 = d / det; - double b2 = -b / det; - double tx2 = (b * ty - tx * d) / det; - double c2 = -c / det; - double d2 = a / det; - double ty2 = (tx * c - a * ty) / det; - - Matrix ret = new Matrix(); - ret.scaleX = a2; - ret.rotateSkew0 = c2; - ret.rotateSkew1 = b2; - ret.scaleY = d2; - ret.translateX = tx2; - ret.translateY = ty2; - return ret; - } - - public double getTotalSkewAngleX() { - Point px = deltaTransform(new Point(0, 1)); - return ((180 / Math.PI) * Math.atan2(px.y, px.x) - 90); - } - - public double getTotalSkewAngleY() { - Point py = deltaTransform(new Point(1, 0)); - return ((180 / Math.PI) * Math.atan2(py.y, py.x)); - } - - public double getTotalScaleX() { - return Math.sqrt(scaleX * scaleX + rotateSkew0 * rotateSkew0); - } - - public double getTotalScaleY() { - return Math.sqrt(rotateSkew1 * rotateSkew1 + scaleY * scaleY); - } - - private int fromFloat(double f) { - return (int) (f * (1 << 16)); - } - - public MATRIX toMATRIX() { - MATRIX result = new MATRIX(); - - result.translateX = (int) translateX; - result.translateY = (int) translateY; - result.hasRotate = true; - result.hasScale = true; - result.scaleX = fromFloat(scaleX); - result.scaleY = fromFloat(scaleY); - result.rotateSkew0 = fromFloat(rotateSkew0); - result.rotateSkew1 = fromFloat(rotateSkew1); - return result; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.exporters.commonshape; + +import com.jpexs.decompiler.flash.types.MATRIX; +import java.awt.geom.AffineTransform; + +/** + * + * @author JPEXS + */ +public final class Matrix implements Cloneable { + + public double scaleX = 1; + + public double scaleY = 1; + + public double rotateSkew0; + + public double rotateSkew1; + + public double translateX; + + public double translateY; + + public static Matrix getScaleInstance(double scale) { + Matrix mat = new Matrix(); + mat.scale(scale); + return mat; + } + + public static Matrix getTranslateInstance(double x, double y) { + Matrix mat = new Matrix(); + mat.translate(x, y); + return mat; + } + + public Matrix() { + scaleX = 1; + scaleY = 1; + } + + public Matrix(MATRIX matrix) { + if (matrix == null) { + matrix = new MATRIX(); + } + translateX = matrix.translateX; + translateY = matrix.translateY; + if (matrix.hasScale) { + scaleX = matrix.getScaleXFloat(); + scaleY = matrix.getScaleYFloat(); + } else { + scaleX = 1; + scaleY = 1; + } + if (matrix.hasRotate) { + rotateSkew0 = matrix.getRotateSkew0Float(); + rotateSkew1 = matrix.getRotateSkew1Float(); + } + } + + public Matrix(AffineTransform transform) { + this(); + if (transform != null) { + scaleX = transform.getScaleX(); + rotateSkew1 = transform.getShearX(); + translateX = transform.getTranslateX(); + rotateSkew0 = transform.getShearY(); + scaleY = transform.getScaleY(); + translateY = transform.getTranslateY(); + } + } + + @Override + public Matrix clone() { + try { + Matrix mat = (Matrix) super.clone(); + return mat; + } catch (CloneNotSupportedException ex) { + throw new RuntimeException(); + } + } + + public Point transform(double x, double y) { + Point result = new Point( + scaleX * x + rotateSkew1 * y + translateX, + rotateSkew0 * x + scaleY * y + translateY); + return result; + } + + public Point transform(Point point) { + return transform(point.x, point.y); + } + + public Point deltaTransform(double x, double y) { + Point result = new Point( + scaleX * x + rotateSkew1 * y, + rotateSkew0 * x + scaleY * y); + return result; + } + + public Point deltaTransform(Point point) { + return deltaTransform(point.x, point.y); + } + + public java.awt.Point deltaTransform(java.awt.Point point) { + Point p = deltaTransform(point.x, point.y); + return new java.awt.Point((int) p.x, (int) p.y); + } + + public java.awt.Point transform(java.awt.Point point) { + Point p = transform(point.x, point.y); + return new java.awt.Point((int) p.x, (int) p.y); + } + + public ExportRectangle transform(ExportRectangle rect) { + double minX = Double.MAX_VALUE; + double minY = Double.MAX_VALUE; + double maxX = Double.MIN_VALUE; + double maxY = Double.MIN_VALUE; + Point point; + point = transform(rect.xMin, rect.yMin); + if (point.x < minX) { + minX = point.x; + } + if (point.x > maxX) { + maxX = point.x; + } + if (point.y < minY) { + minY = point.y; + } + if (point.y > maxY) { + maxY = point.y; + } + point = transform(rect.xMax, rect.yMin); + if (point.x < minX) { + minX = point.x; + } + if (point.x > maxX) { + maxX = point.x; + } + if (point.y < minY) { + minY = point.y; + } + if (point.y > maxY) { + maxY = point.y; + } + point = transform(rect.xMin, rect.yMax); + if (point.x < minX) { + minX = point.x; + } + if (point.x > maxX) { + maxX = point.x; + } + if (point.y < minY) { + minY = point.y; + } + if (point.y > maxY) { + maxY = point.y; + } + point = transform(rect.xMax, rect.yMax); + if (point.x < minX) { + minX = point.x; + } + if (point.x > maxX) { + maxX = point.x; + } + if (point.y < minY) { + minY = point.y; + } + if (point.y > maxY) { + maxY = point.y; + } + return new ExportRectangle(minX, minY, maxX, maxY); + } + + public void translate(double x, double y) { + translateX = scaleX * x + rotateSkew1 * y + translateX; + translateY = rotateSkew0 * x + scaleY * y + translateY; + } + + public void scale(double factor) { + scaleX *= factor; + scaleY *= factor; + rotateSkew0 *= factor; + rotateSkew1 *= factor; + } + + public Matrix concatenate(Matrix m) { + Matrix result = new Matrix(); + result.scaleX = scaleX * m.scaleX + rotateSkew1 * m.rotateSkew0; + result.rotateSkew0 = rotateSkew0 * m.scaleX + scaleY * m.rotateSkew0; + result.rotateSkew1 = scaleX * m.rotateSkew1 + rotateSkew1 * m.scaleY; + result.scaleY = rotateSkew0 * m.rotateSkew1 + scaleY * m.scaleY; + result.translateX = scaleX * m.translateX + rotateSkew1 * m.translateY + translateX; + result.translateY = rotateSkew0 * m.translateX + scaleY * m.translateY + translateY; + return result; + } + + public Matrix preConcatenate(Matrix m) { + Matrix result = new Matrix(); + result.scaleX = m.scaleX * scaleX + m.rotateSkew1 * rotateSkew0; + result.rotateSkew0 = m.rotateSkew0 * scaleX + m.scaleY * rotateSkew0; + result.rotateSkew1 = m.scaleX * rotateSkew1 + m.rotateSkew1 * scaleY; + result.scaleY = m.rotateSkew0 * rotateSkew1 + m.scaleY * scaleY; + result.translateX = m.scaleX * translateX + m.rotateSkew1 * translateY + m.translateX; + result.translateY = m.rotateSkew0 * translateX + m.scaleY * translateY + m.translateY; + return result; + } + + public AffineTransform toTransform() { + AffineTransform transform = new AffineTransform(scaleX, rotateSkew0, + rotateSkew1, scaleY, + translateX, translateY); + return transform; + } + + public String getSvgTransformationString(double translateDivisor, double unitDivisor) { + double translateX = roundPixels400(this.translateX / translateDivisor); + double translateY = roundPixels400(this.translateY / translateDivisor); + double rotateSkew0 = roundPixels400(this.rotateSkew0 / unitDivisor); + double rotateSkew1 = roundPixels400(this.rotateSkew1 / unitDivisor); + double scaleX = roundPixels400(this.scaleX / unitDivisor); + double scaleY = roundPixels400(this.scaleY / unitDivisor); + return "matrix(" + scaleX + ", " + rotateSkew0 + ", " + + rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")"; + } + + public static String[] parseSvgNumberList(String params) { + while (params.contains(" ")) { + params = params.replaceAll(" ", " "); + } + + params = params.trim(); + params = params.replace(", ", ","); + params = params.replace(" ", ","); + String[] args = params.split(","); + return args; + } + + public static Matrix parseSvgMatrix(String transformStr, double translateDivisor, double unitDivisor) { + Matrix ret = new Matrix(); + while (transformStr != null && transformStr.length() > 0) { + String funcName = transformStr.split("\\(")[0]; + transformStr = transformStr.substring(funcName.length() + 1); + String params = transformStr.split("\\)")[0]; + transformStr = transformStr.substring(params.length() + 1).trim(); + String[] args = parseSvgNumberList(params); + funcName = funcName.trim(); + switch (funcName) { + case "matrix": + if (args.length == 6) { + double scaleX = Double.parseDouble(args[0].trim()); + double rotateSkew0 = Double.parseDouble(args[1].trim()); + double rotateSkew1 = Double.parseDouble(args[2].trim()); + double scaleY = Double.parseDouble(args[3].trim()); + double translateX = Double.parseDouble(args[4].trim()); + double translateY = Double.parseDouble(args[5].trim()); + Matrix result = new Matrix(); + result.translateX = translateX; + result.translateY = translateY; + result.rotateSkew0 = rotateSkew0; + result.rotateSkew1 = rotateSkew1; + result.scaleX = scaleX; + result.scaleY = scaleY; + ret = ret.concatenate(result); + } + break; + case "translate": + if (args.length == 1 || args.length == 2) { + double translateX = Double.parseDouble(args[0].trim()); + double translateY = 0; + if (args.length == 2) { + translateY = Double.parseDouble(args[1].trim()); + } + + Matrix result = new Matrix(); + result.translateX = translateX; + result.translateY = translateY; + ret = ret.concatenate(result); + } + break; + case "scale": + if (args.length == 1 || args.length == 2) { + double scaleX = Double.parseDouble(args[0].trim()); + double scaleY = scaleX; + if (args.length == 2) { + scaleY = Double.parseDouble(args[1].trim()); + } + + Matrix result = new Matrix(); + result.scaleX = scaleX; + result.scaleY = scaleY; + ret = ret.concatenate(result); + } + break; + case "skewX": + if (args.length == 1) { + double angle = Double.parseDouble(args[0].trim()) * Math.PI / 180; + + Matrix result = new Matrix(); + result.rotateSkew1 = Math.tan(angle); + ret = ret.concatenate(result); + } + break; + case "skewY": + if (args.length == 1) { + double angle = Double.parseDouble(args[0].trim()) * Math.PI / 180; + + Matrix result = new Matrix(); + result.rotateSkew0 = Math.tan(angle); + ret = ret.concatenate(result); + } + break; + case "rotate": + if (args.length == 1 || args.length == 3) { + double rotateAngle = Double.parseDouble(args[0].trim()); + double tx = 0; + double ty = 0; + if (args.length > 1) { + tx = Double.parseDouble(args[1].trim()); + ty = Double.parseDouble(args[2].trim()); + } + + double angleRad = -rotateAngle * Math.PI / 180; + Matrix result = new Matrix(); + result.rotateSkew0 = -Math.sin(angleRad); + result.rotateSkew1 = Math.sin(angleRad); + result.scaleX = Math.cos(angleRad); + result.scaleY = Math.cos(angleRad); + result = result.preConcatenate(getTranslateInstance(tx, ty)) + .concatenate(getTranslateInstance(-tx, -ty)); + ret = ret.concatenate(result); + } + break; + } + } + + ret.translateX *= translateDivisor; + ret.translateY *= translateDivisor; + ret.rotateSkew0 *= unitDivisor; + ret.rotateSkew1 *= unitDivisor; + ret.scaleX *= unitDivisor; + ret.scaleY *= unitDivisor; + return ret; + } + + private double roundPixels400(double pixels) { + return Math.round(pixels * 10000) / 10000.0; + } + + @Override + public String toString() { + return "[Matrix scale:" + scaleX + "," + scaleY + ", rotate:" + rotateSkew0 + "," + rotateSkew1 + ", translate:" + translateX + "," + translateY + "]"; + } + + public Matrix inverse() { + double a = scaleX; + double b = rotateSkew1; + double tx = translateX; + double c = rotateSkew0; + double d = scaleY; + double ty = translateY; + + double det = a * d - b * c; + + double a2 = d / det; + double b2 = -b / det; + double tx2 = (b * ty - tx * d) / det; + double c2 = -c / det; + double d2 = a / det; + double ty2 = (tx * c - a * ty) / det; + + Matrix ret = new Matrix(); + ret.scaleX = a2; + ret.rotateSkew0 = c2; + ret.rotateSkew1 = b2; + ret.scaleY = d2; + ret.translateX = tx2; + ret.translateY = ty2; + return ret; + } + + public double getTotalSkewAngleX() { + Point px = deltaTransform(new Point(0, 1)); + return ((180 / Math.PI) * Math.atan2(px.y, px.x) - 90); + } + + public double getTotalSkewAngleY() { + Point py = deltaTransform(new Point(1, 0)); + return ((180 / Math.PI) * Math.atan2(py.y, py.x)); + } + + public double getTotalScaleX() { + return Math.sqrt(scaleX * scaleX + rotateSkew0 * rotateSkew0); + } + + public double getTotalScaleY() { + return Math.sqrt(rotateSkew1 * rotateSkew1 + scaleY * scaleY); + } + + private int fromFloat(double f) { + return (int) (f * (1 << 16)); + } + + public MATRIX toMATRIX() { + MATRIX result = new MATRIX(); + + result.translateX = (int) translateX; + result.translateY = (int) translateY; + result.hasRotate = true; + result.hasScale = true; + result.scaleX = fromFloat(scaleX); + result.scaleY = fromFloat(scaleY); + result.rotateSkew0 = fromFloat(rotateSkew0); + result.rotateSkew1 = fromFloat(rotateSkew1); + return result; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/NulWriter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/NulWriter.java index bd5d93f3b..2b8252896 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/NulWriter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/NulWriter.java @@ -1,162 +1,162 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.helpers; - -import com.jpexs.decompiler.flash.helpers.hilight.HighlightData; -import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; -import java.util.Stack; - -/** - * Provides methods for highlighting positions of instructions in the text. - * - * @author JPEXS - */ -public class NulWriter extends GraphTextWriter { - - private final Stack loopStack = new Stack<>(); - - private final Stack stringAddedStack = new Stack<>(); - - private boolean stringAdded = false; - - public NulWriter() { - super(new CodeFormatting()); - } - - public void startLoop(long loopId, int loopType) { - LoopWithType loop = new LoopWithType(); - loop.loopId = loopId; - loop.type = loopType; - loopStack.add(loop); - } - - public LoopWithType endLoop(long loopId) { - LoopWithType loopIdInStack = loopStack.pop(); - if (loopId != loopIdInStack.loopId) { - throw new Error("LoopId mismatch"); - } - return loopIdInStack; - } - - public long getLoop() { - if (loopStack.isEmpty()) { - return -1; - } - return loopStack.peek().loopId; - } - - public long getNonSwitchLoop() { - if (loopStack.isEmpty()) { - return -1; - } - - int pos = loopStack.size() - 1; - LoopWithType loop; - do { - loop = loopStack.get(pos); - pos--; - } while ((pos >= 0) && (loop.type == LoopWithType.LOOP_TYPE_SWITCH)); - - if (loop.type == LoopWithType.LOOP_TYPE_SWITCH) { - return -1; - } - - return loop.loopId; - } - - public void setLoopUsed(long loopId) { - if (loopStack.isEmpty()) { - return; - } - - int pos = loopStack.size() - 1; - LoopWithType loop = null; - do { - loop = loopStack.get(pos); - pos--; - } while ((pos >= 0) && (loop.loopId != loopId)); - - if (loop.loopId == loopId) { - loop.used = true; - } - } - - @Override - public NulWriter hilightSpecial(String text, HighlightSpecialType type, String specialValue, HighlightData data) { - stringAdded = true; - return this; - } - - @Override - public GraphTextWriter append(char value) { - stringAdded = true; - return this; - } - - @Override - public GraphTextWriter append(int value) { - stringAdded = true; - return this; - } - - @Override - public GraphTextWriter append(long value) { - stringAdded = true; - return this; - } - - @Override - public NulWriter append(String str) { - stringAdded = true; - return this; - } - - @Override - public GraphTextWriter appendWithData(String str, HighlightData data) { - stringAdded = true; - return this; - } - - @Override - public NulWriter append(String str, long offset, long fileOffset) { - stringAdded = true; - return this; - } - - @Override - public NulWriter appendNoHilight(int i) { - stringAdded = true; - return this; - } - - @Override - public NulWriter appendNoHilight(String str) { - stringAdded = true; - return this; - } - - public void mark() { - stringAddedStack.add(stringAdded); - stringAdded = false; - } - - public boolean getMark() { - boolean result = stringAdded; - stringAdded = stringAddedStack.pop() || result; - return result; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.helpers; + +import com.jpexs.decompiler.flash.helpers.hilight.HighlightData; +import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; +import java.util.Stack; + +/** + * Provides methods for highlighting positions of instructions in the text. + * + * @author JPEXS + */ +public class NulWriter extends GraphTextWriter { + + private final Stack loopStack = new Stack<>(); + + private final Stack stringAddedStack = new Stack<>(); + + private boolean stringAdded = false; + + public NulWriter() { + super(new CodeFormatting()); + } + + public void startLoop(long loopId, int loopType) { + LoopWithType loop = new LoopWithType(); + loop.loopId = loopId; + loop.type = loopType; + loopStack.add(loop); + } + + public LoopWithType endLoop(long loopId) { + LoopWithType loopIdInStack = loopStack.pop(); + if (loopId != loopIdInStack.loopId) { + throw new Error("LoopId mismatch"); + } + return loopIdInStack; + } + + public long getLoop() { + if (loopStack.isEmpty()) { + return -1; + } + return loopStack.peek().loopId; + } + + public long getNonSwitchLoop() { + if (loopStack.isEmpty()) { + return -1; + } + + int pos = loopStack.size() - 1; + LoopWithType loop; + do { + loop = loopStack.get(pos); + pos--; + } while ((pos >= 0) && (loop.type == LoopWithType.LOOP_TYPE_SWITCH)); + + if (loop.type == LoopWithType.LOOP_TYPE_SWITCH) { + return -1; + } + + return loop.loopId; + } + + public void setLoopUsed(long loopId) { + if (loopStack.isEmpty()) { + return; + } + + int pos = loopStack.size() - 1; + LoopWithType loop = null; + do { + loop = loopStack.get(pos); + pos--; + } while ((pos >= 0) && (loop.loopId != loopId)); + + if (loop.loopId == loopId) { + loop.used = true; + } + } + + @Override + public NulWriter hilightSpecial(String text, HighlightSpecialType type, String specialValue, HighlightData data) { + stringAdded = true; + return this; + } + + @Override + public GraphTextWriter append(char value) { + stringAdded = true; + return this; + } + + @Override + public GraphTextWriter append(int value) { + stringAdded = true; + return this; + } + + @Override + public GraphTextWriter append(long value) { + stringAdded = true; + return this; + } + + @Override + public NulWriter append(String str) { + stringAdded = true; + return this; + } + + @Override + public GraphTextWriter appendWithData(String str, HighlightData data) { + stringAdded = true; + return this; + } + + @Override + public NulWriter append(String str, long offset, long fileOffset) { + stringAdded = true; + return this; + } + + @Override + public NulWriter appendNoHilight(int i) { + stringAdded = true; + return this; + } + + @Override + public NulWriter appendNoHilight(String str) { + stringAdded = true; + return this; + } + + public void mark() { + stringAddedStack.add(stringAdded); + stringAdded = false; + } + + public boolean getMark() { + boolean result = stringAdded; + stringAdded = stringAddedStack.pop() || result; + return result; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources.properties b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources.properties index d15c905c2..ce6af2bd8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources.properties +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources.properties @@ -1,38 +1,38 @@ -# Copyright (C) 2010-2016 JPEXS, All rights reserved. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 3.0 of the License, or (at your option) any later version. -# -# This library 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library. - -decompilationError = Decompilation error -decompilationError.timeout = Timeout ({0}) was reached -decompilationError.timeout.description = Not decompiled due to timeout -decompilationError.obfuscated = Code may be obfuscated -decompilationError.errorType = Error type -decompilationError.error.description = Not decompiled due to error -decompilationError.actionCount = Action count: -decompilationError.instructionCount = Instruction count: - -decompilation.skipped = Decompilation skipped -decompilation.unsupported = Unsupported by decompiler -decompilerMark = decompiler mark - -#example: 1 hour and 2 minutes -timeFormat.and = and -timeFormat.hour = hour -timeFormat.hours = hours -timeFormat.minute = minute -timeFormat.minutes = minutes -timeFormat.second = second -timeFormat.seconds = seconds - -fontNotFound = Font with id=%fontId% was not found. +# Copyright (C) 2010-2016 JPEXS, All rights reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3.0 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. + +decompilationError = Decompilation error +decompilationError.timeout = Timeout ({0}) was reached +decompilationError.timeout.description = Not decompiled due to timeout +decompilationError.obfuscated = Code may be obfuscated +decompilationError.errorType = Error type +decompilationError.error.description = Not decompiled due to error +decompilationError.actionCount = Action count: +decompilationError.instructionCount = Instruction count: + +decompilation.skipped = Decompilation skipped +decompilation.unsupported = Unsupported by decompiler +decompilerMark = decompiler mark + +#example: 1 hour and 2 minutes +timeFormat.and = and +timeFormat.hour = hour +timeFormat.hours = hours +timeFormat.minute = minute +timeFormat.minutes = minutes +timeFormat.second = second +timeFormat.seconds = seconds + +fontNotFound = Font with id=%fontId% was not found. diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java index e1dff7a29..2d5b730e6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java @@ -1,177 +1,177 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.FontInfoTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.LANGCODE; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.annotations.SWFVersion; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -@SWFVersion(from = 6) -public class DefineFontInfo2Tag extends FontInfoTag { - - public static final int ID = 62; - - public static final String NAME = "DefineFontInfo2"; - - public String fontName; - - @Reserved - @SWFType(value = BasicType.UB, count = 2) - public int reserved; - - public boolean fontFlagsSmallText; - - public boolean fontFlagsShiftJIS; - - public boolean fontFlagsANSI; - - public boolean fontFlagsItalic; - - public boolean fontFlagsBold; - - public boolean fontFlagsWideCodes; //always 1 - - public LANGCODE languageCode; - - @SWFType(BasicType.UI16) - public List codeTable; - - /** - * Constructor - * - * @param swf - */ - public DefineFontInfo2Tag(SWF swf) { - super(swf, ID, NAME, null); - fontName = "New Font Info Name"; - languageCode = new LANGCODE(); - codeTable = new ArrayList<>(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineFontInfo2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, NAME, data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontID = sis.readUI16("fontID"); - if (swf.version >= 6) { - fontName = sis.readNetString("fontName", Utf8Helper.charset); - } else { - fontName = sis.readNetString("fontName"); - } - reserved = (int) sis.readUB(2, "reserved"); - fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; - fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; - fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1; - fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; - fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; - fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; //Always 1 - languageCode = sis.readLANGCODE("languageCode"); - int ctLen = sis.available() / 2; - codeTable = new ArrayList<>(); - for (int i = 0; i < ctLen; i++) { - codeTable.add(sis.readUI16("code")); - } - } - - /** - * Gets data bytes - * - * @param sos SWF output stream - * @throws java.io.IOException - */ - @Override - public void getData(SWFOutputStream sos) throws IOException { - sos.writeUI16(fontID); - if (swf.version >= 6) { - sos.writeNetString(fontName, Utf8Helper.charset); - } else { - sos.writeNetString(fontName); - } - sos.writeUB(2, reserved); - sos.writeUB(1, fontFlagsSmallText ? 1 : 0); - sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); - sos.writeUB(1, fontFlagsANSI ? 1 : 0); - sos.writeUB(1, fontFlagsItalic ? 1 : 0); - sos.writeUB(1, fontFlagsBold ? 1 : 0); - sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); - sos.writeLANGCODE(languageCode); - for (int c : codeTable) { - sos.writeUI16(c); - } - } - - @Override - public List getCodeTable() { - return codeTable; - } - - @Override - public void addCharacter(int index, int character) { - codeTable.add(index, character); - setModified(true); - } - - @Override - public String getFontName() { - return fontName; - } - - @Override - public boolean getFontFlagsBold() { - return fontFlagsBold; - } - - @Override - public void setFontFlagsBold(boolean value) { - fontFlagsBold = value; - } - - @Override - public boolean getFontFlagsItalic() { - return fontFlagsItalic; - } - - @Override - public void setFontFlagsItalic(boolean value) { - fontFlagsItalic = value; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.FontInfoTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.LANGCODE; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.annotations.SWFVersion; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +@SWFVersion(from = 6) +public class DefineFontInfo2Tag extends FontInfoTag { + + public static final int ID = 62; + + public static final String NAME = "DefineFontInfo2"; + + public String fontName; + + @Reserved + @SWFType(value = BasicType.UB, count = 2) + public int reserved; + + public boolean fontFlagsSmallText; + + public boolean fontFlagsShiftJIS; + + public boolean fontFlagsANSI; + + public boolean fontFlagsItalic; + + public boolean fontFlagsBold; + + public boolean fontFlagsWideCodes; //always 1 + + public LANGCODE languageCode; + + @SWFType(BasicType.UI16) + public List codeTable; + + /** + * Constructor + * + * @param swf + */ + public DefineFontInfo2Tag(SWF swf) { + super(swf, ID, NAME, null); + fontName = "New Font Info Name"; + languageCode = new LANGCODE(); + codeTable = new ArrayList<>(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineFontInfo2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + fontID = sis.readUI16("fontID"); + if (swf.version >= 6) { + fontName = sis.readNetString("fontName", Utf8Helper.charset); + } else { + fontName = sis.readNetString("fontName"); + } + reserved = (int) sis.readUB(2, "reserved"); + fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; + fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; + fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1; + fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; + fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; + fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; //Always 1 + languageCode = sis.readLANGCODE("languageCode"); + int ctLen = sis.available() / 2; + codeTable = new ArrayList<>(); + for (int i = 0; i < ctLen; i++) { + codeTable.add(sis.readUI16("code")); + } + } + + /** + * Gets data bytes + * + * @param sos SWF output stream + * @throws java.io.IOException + */ + @Override + public void getData(SWFOutputStream sos) throws IOException { + sos.writeUI16(fontID); + if (swf.version >= 6) { + sos.writeNetString(fontName, Utf8Helper.charset); + } else { + sos.writeNetString(fontName); + } + sos.writeUB(2, reserved); + sos.writeUB(1, fontFlagsSmallText ? 1 : 0); + sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); + sos.writeUB(1, fontFlagsANSI ? 1 : 0); + sos.writeUB(1, fontFlagsItalic ? 1 : 0); + sos.writeUB(1, fontFlagsBold ? 1 : 0); + sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); + sos.writeLANGCODE(languageCode); + for (int c : codeTable) { + sos.writeUI16(c); + } + } + + @Override + public List getCodeTable() { + return codeTable; + } + + @Override + public void addCharacter(int index, int character) { + codeTable.add(index, character); + setModified(true); + } + + @Override + public String getFontName() { + return fontName; + } + + @Override + public boolean getFontFlagsBold() { + return fontFlagsBold; + } + + @Override + public void setFontFlagsBold(boolean value) { + fontFlagsBold = value; + } + + @Override + public boolean getFontFlagsItalic() { + return fontFlagsItalic; + } + + @Override + public void setFontFlagsItalic(boolean value) { + fontFlagsItalic = value; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java index 396dd4c8d..a5d0158b6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java @@ -1,178 +1,178 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.FontInfoTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.annotations.SWFVersion; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -@SWFVersion(from = 1) -public class DefineFontInfoTag extends FontInfoTag { - - public static final int ID = 13; - - public static final String NAME = "DefineFontInfo"; - - public String fontName; - - @Reserved - @SWFType(value = BasicType.UB, count = 2) - public int reserved; - - public boolean fontFlagsSmallText; - - public boolean fontFlagsShiftJIS; - - public boolean fontFlagsANSI; - - public boolean fontFlagsItalic; - - public boolean fontFlagsBold; - - public boolean fontFlagsWideCodes; - - @SWFType(value = BasicType.UI8, alternateValue = BasicType.UI16, alternateCondition = "fontFlagsWideCodes") - public List codeTable; - - /** - * Constructor - * - * @param swf - */ - public DefineFontInfoTag(SWF swf) { - super(swf, ID, NAME, null); - fontName = "New Font Info Name"; - codeTable = new ArrayList<>(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineFontInfoTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, NAME, data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontID = sis.readUI16("fontId"); - if (swf.version >= 6) { - fontName = sis.readNetString("fontName", Utf8Helper.charset); - } else { - fontName = sis.readNetString("fontName"); - } - reserved = (int) sis.readUB(2, "reserved"); - fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; - fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; - fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1; - fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; - fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; - fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; - codeTable = new ArrayList<>(); - while (sis.available() > 0) { - if (fontFlagsWideCodes) { - codeTable.add(sis.readUI16("code")); - } else { - codeTable.add(sis.readUI8("code")); - } - } - } - - /** - * Gets data bytes - * - * @param sos SWF output stream - * @throws java.io.IOException - */ - @Override - public void getData(SWFOutputStream sos) throws IOException { - sos.writeUI16(fontID); - if (swf.version >= 6) { - sos.writeNetString(fontName, Utf8Helper.charset); - } else { - sos.writeNetString(fontName); - } - sos.writeUB(2, reserved); - sos.writeUB(1, fontFlagsSmallText ? 1 : 0); - sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); - sos.writeUB(1, fontFlagsANSI ? 1 : 0); - sos.writeUB(1, fontFlagsItalic ? 1 : 0); - sos.writeUB(1, fontFlagsBold ? 1 : 0); - sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); - for (int code : codeTable) { - if (fontFlagsWideCodes) { - sos.writeUI16(code); - } else { - sos.writeUI8(code); - } - } - } - - @Override - public List getCodeTable() { - return codeTable; - } - - @Override - public void addCharacter(int index, int character) { - codeTable.add(index, character); - setModified(true); - } - - @Override - public String getFontName() { - return fontName; - } - - @Override - public boolean getFontFlagsBold() { - return fontFlagsBold; - } - - @Override - public void setFontFlagsBold(boolean value) { - fontFlagsBold = value; - } - - @Override - public boolean getFontFlagsItalic() { - return fontFlagsItalic; - } - - @Override - public void setFontFlagsItalic(boolean value) { - fontFlagsItalic = value; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.FontInfoTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.annotations.SWFVersion; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +@SWFVersion(from = 1) +public class DefineFontInfoTag extends FontInfoTag { + + public static final int ID = 13; + + public static final String NAME = "DefineFontInfo"; + + public String fontName; + + @Reserved + @SWFType(value = BasicType.UB, count = 2) + public int reserved; + + public boolean fontFlagsSmallText; + + public boolean fontFlagsShiftJIS; + + public boolean fontFlagsANSI; + + public boolean fontFlagsItalic; + + public boolean fontFlagsBold; + + public boolean fontFlagsWideCodes; + + @SWFType(value = BasicType.UI8, alternateValue = BasicType.UI16, alternateCondition = "fontFlagsWideCodes") + public List codeTable; + + /** + * Constructor + * + * @param swf + */ + public DefineFontInfoTag(SWF swf) { + super(swf, ID, NAME, null); + fontName = "New Font Info Name"; + codeTable = new ArrayList<>(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineFontInfoTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + fontID = sis.readUI16("fontId"); + if (swf.version >= 6) { + fontName = sis.readNetString("fontName", Utf8Helper.charset); + } else { + fontName = sis.readNetString("fontName"); + } + reserved = (int) sis.readUB(2, "reserved"); + fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; + fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; + fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1; + fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; + fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; + fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; + codeTable = new ArrayList<>(); + while (sis.available() > 0) { + if (fontFlagsWideCodes) { + codeTable.add(sis.readUI16("code")); + } else { + codeTable.add(sis.readUI8("code")); + } + } + } + + /** + * Gets data bytes + * + * @param sos SWF output stream + * @throws java.io.IOException + */ + @Override + public void getData(SWFOutputStream sos) throws IOException { + sos.writeUI16(fontID); + if (swf.version >= 6) { + sos.writeNetString(fontName, Utf8Helper.charset); + } else { + sos.writeNetString(fontName); + } + sos.writeUB(2, reserved); + sos.writeUB(1, fontFlagsSmallText ? 1 : 0); + sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); + sos.writeUB(1, fontFlagsANSI ? 1 : 0); + sos.writeUB(1, fontFlagsItalic ? 1 : 0); + sos.writeUB(1, fontFlagsBold ? 1 : 0); + sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); + for (int code : codeTable) { + if (fontFlagsWideCodes) { + sos.writeUI16(code); + } else { + sos.writeUI8(code); + } + } + } + + @Override + public List getCodeTable() { + return codeTable; + } + + @Override + public void addCharacter(int index, int character) { + codeTable.add(index, character); + setModified(true); + } + + @Override + public String getFontName() { + return fontName; + } + + @Override + public boolean getFontFlagsBold() { + return fontFlagsBold; + } + + @Override + public void setFontFlagsBold(boolean value) { + fontFlagsBold = value; + } + + @Override + public boolean getFontFlagsItalic() { + return fontFlagsItalic; + } + + @Override + public void setFontFlagsItalic(boolean value) { + fontFlagsItalic = value; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java index ea53f2642..a2897ffad 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java @@ -1,224 +1,224 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.DisassemblyListener; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.action.Action; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.flash.tags.base.ASMSource; -import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.decompiler.flash.types.annotations.SWFVersion; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Helper; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * Instructs Flash Player to perform a list of actions when the current frame is - * complete. - * - * @author JPEXS - */ -@SWFVersion(from = 1) -public class DoActionTag extends Tag implements ASMSource { - - public static final int ID = 12; - - public static final String NAME = "DoAction"; - - /** - * List of actions to perform - */ - @HideInRawEdit - public ByteArrayRange actionBytes; - - @Internal - private String scriptName = "-"; - - @Override - public String getScriptName() { - return scriptName; - } - - /** - * Constructor - * - * @param swf - */ - public DoActionTag(SWF swf) { - super(swf, ID, NAME, null); - actionBytes = ByteArrayRange.EMPTY; - } - - /** - * Constructor - * - * @param swf - * @param data - */ - public DoActionTag(SWF swf, ByteArrayRange data) { - super(swf, ID, NAME, data); - actionBytes = ByteArrayRange.EMPTY; - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws java.io.IOException - */ - public DoActionTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, NAME, data); - readData(sis, data, 0, false, false, false); - } - - @Override - public void setScriptName(String scriptName) { - this.scriptName = scriptName; - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes"); - } - - /** - * Gets data bytes - * - * @param sos SWF output stream - * @throws java.io.IOException - */ - @Override - public void getData(SWFOutputStream sos) throws IOException { - sos.write(getActionBytes()); - } - - /** - * Converts actions to ASM source - * - * @param exportMode PCode or hex? - * @param writer - * @param actions - * @return ASM source - * @throws java.lang.InterruptedException - */ - @Override - public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException { - if (actions == null) { - actions = getActions(); - } - - return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer); - } - - /** - * Whether or not this object contains ASM source - * - * @return True when contains - */ - @Override - public boolean containsSource() { - return true; - } - - @Override - public ActionList getActions() throws InterruptedException { - return SWF.getCachedActionList(this, listeners); - } - - @Override - public void setActions(List actions) { - actionBytes = Action.actionsToByteArrayRange(actions, true, swf.version); - } - - @Override - public ByteArrayRange getActionBytes() { - return actionBytes; - } - - @Override - public void setActionBytes(byte[] actionBytes) { - this.actionBytes = new ByteArrayRange(actionBytes); - SWF.uncache(this); - } - - @Override - public void setConstantPools(List> constantPools) throws ConstantPoolTooBigException { - Action.setConstantPools(this, constantPools, false); - } - - @Override - public void setModified() { - setModified(true); - } - - @Override - public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) { - return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData()); - } - - List listeners = new ArrayList<>(); - - @Override - public void addDisassemblyListener(DisassemblyListener listener) { - listeners.add(listener); - } - - @Override - public void removeDisassemblyListener(DisassemblyListener listener) { - listeners.remove(listener); - } - - @Override - public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { - return writer; - } - - @Override - public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) { - return writer; - } - - @Override - public int getPrefixLineCount() { - return 0; - } - - @Override - public String removePrefixAndSuffix(String source) { - return source; - } - - @Override - public Tag getSourceTag() { - return this; - } - - @Override - public void setSourceTag(Tag t) { - //nothing - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.DisassemblyListener; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.SWFVersion; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Helper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Instructs Flash Player to perform a list of actions when the current frame is + * complete. + * + * @author JPEXS + */ +@SWFVersion(from = 1) +public class DoActionTag extends Tag implements ASMSource { + + public static final int ID = 12; + + public static final String NAME = "DoAction"; + + /** + * List of actions to perform + */ + @HideInRawEdit + public ByteArrayRange actionBytes; + + @Internal + private String scriptName = "-"; + + @Override + public String getScriptName() { + return scriptName; + } + + /** + * Constructor + * + * @param swf + */ + public DoActionTag(SWF swf) { + super(swf, ID, NAME, null); + actionBytes = ByteArrayRange.EMPTY; + } + + /** + * Constructor + * + * @param swf + * @param data + */ + public DoActionTag(SWF swf, ByteArrayRange data) { + super(swf, ID, NAME, data); + actionBytes = ByteArrayRange.EMPTY; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws java.io.IOException + */ + public DoActionTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public void setScriptName(String scriptName) { + this.scriptName = scriptName; + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes"); + } + + /** + * Gets data bytes + * + * @param sos SWF output stream + * @throws java.io.IOException + */ + @Override + public void getData(SWFOutputStream sos) throws IOException { + sos.write(getActionBytes()); + } + + /** + * Converts actions to ASM source + * + * @param exportMode PCode or hex? + * @param writer + * @param actions + * @return ASM source + * @throws java.lang.InterruptedException + */ + @Override + public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException { + if (actions == null) { + actions = getActions(); + } + + return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer); + } + + /** + * Whether or not this object contains ASM source + * + * @return True when contains + */ + @Override + public boolean containsSource() { + return true; + } + + @Override + public ActionList getActions() throws InterruptedException { + return SWF.getCachedActionList(this, listeners); + } + + @Override + public void setActions(List actions) { + actionBytes = Action.actionsToByteArrayRange(actions, true, swf.version); + } + + @Override + public ByteArrayRange getActionBytes() { + return actionBytes; + } + + @Override + public void setActionBytes(byte[] actionBytes) { + this.actionBytes = new ByteArrayRange(actionBytes); + SWF.uncache(this); + } + + @Override + public void setConstantPools(List> constantPools) throws ConstantPoolTooBigException { + Action.setConstantPools(this, constantPools, false); + } + + @Override + public void setModified() { + setModified(true); + } + + @Override + public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) { + return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData()); + } + + List listeners = new ArrayList<>(); + + @Override + public void addDisassemblyListener(DisassemblyListener listener) { + listeners.add(listener); + } + + @Override + public void removeDisassemblyListener(DisassemblyListener listener) { + listeners.remove(listener); + } + + @Override + public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { + return writer; + } + + @Override + public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) { + return writer; + } + + @Override + public int getPrefixLineCount() { + return 0; + } + + @Override + public String removePrefixAndSuffix(String source) { + return source; + } + + @Override + public Tag getSourceTag() { + return this; + } + + @Override + public void setSourceTag(Tag t) { + //nothing + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java index bf3f8b40c..e0ffddddc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java @@ -1,281 +1,281 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags.base; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; -import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; -import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; -import com.jpexs.decompiler.flash.helpers.ImageHelper; -import com.jpexs.decompiler.flash.tags.TagInfo; -import com.jpexs.decompiler.flash.tags.enums.ImageFormat; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.FILLSTYLE; -import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; -import com.jpexs.decompiler.flash.types.LINESTYLE; -import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import java.awt.Dimension; -import java.awt.Shape; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Set; - -/** - * - * @author JPEXS - */ -public abstract class ImageTag extends DrawableTag { - - @SWFType(BasicType.UI16) - public int characterID; - - protected SerializableImage cachedImage; - - public ImageTag(SWF swf, int id, String name, ByteArrayRange data) { - super(swf, id, name, data); - } - - public abstract InputStream getOriginalImageData(); - - protected abstract SerializableImage getImage(); - - public abstract Dimension getImageDimension(); - - public abstract void setImage(byte[] data) throws IOException; - - public abstract ImageFormat getImageFormat(); - - public abstract ImageFormat getOriginalImageFormat(); - - public boolean importSupported() { - return true; - } - - public static ImageFormat getImageFormat(byte[] data) { - return getImageFormat(new ByteArrayRange(data)); - } - - public static ImageFormat getImageFormat(ByteArrayRange data) { - if (hasErrorHeader(data)) { - return ImageFormat.JPEG; - } - - if (data.getLength() > 2 && ((data.get(0) & 0xff) == 0xff) && ((data.get(1) & 0xff) == 0xd8)) { - return ImageFormat.JPEG; - } - - if (data.getLength() > 6 && ((data.get(0) & 0xff) == 0x47) && ((data.get(1) & 0xff) == 0x49) && ((data.get(2) & 0xff) == 0x46) && ((data.get(3) & 0xff) == 0x38) && ((data.get(4) & 0xff) == 0x39) && ((data.get(5) & 0xff) == 0x61)) { - return ImageFormat.GIF; - } - - if (data.getLength() > 8 && ((data.get(0) & 0xff) == 0x89) && ((data.get(1) & 0xff) == 0x50) && ((data.get(2) & 0xff) == 0x4e) && ((data.get(3) & 0xff) == 0x47) && ((data.get(4) & 0xff) == 0x0d) && ((data.get(5) & 0xff) == 0x0a) && ((data.get(6) & 0xff) == 0x1a) && ((data.get(7) & 0xff) == 0x0a)) { - return ImageFormat.PNG; - } - - return ImageFormat.UNKNOWN; - } - - public SerializableImage getImageCached() { - if (cachedImage != null) { - return cachedImage; - } - - SerializableImage image = getImage(); - if (Configuration.cacheImages.get()) { - cachedImage = image; - } - - return image; - } - - public InputStream getImageData() { - InputStream is = getOriginalImageData(); - if (is != null) { - return is; - } - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ImageHelper.write(getImage().getBufferedImage(), getImageFormat(), baos); - return new ByteArrayInputStream(baos.toByteArray()); - } - - public static boolean hasErrorHeader(byte[] data) { - return hasErrorHeader(new ByteArrayRange(data)); - } - - public static boolean hasErrorHeader(ByteArrayRange data) { - if (data.getLength() > 4) { - if ((data.get(0) & 0xff) == 0xff && (data.get(1) & 0xff) == 0xd9 - && (data.get(2) & 0xff) == 0xff && (data.get(3) & 0xff) == 0xd8) { - return true; - } - } - return false; - } - - private SHAPEWITHSTYLE getShape() { - RECT rect = getRect(); - return getShape(rect, false); - } - - public SHAPEWITHSTYLE getShape(RECT rect, boolean fill) { - boolean translated = rect.Xmin != 0 || rect.Ymin != 0; - SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE(); - shape.fillStyles = new FILLSTYLEARRAY(); - shape.fillStyles.fillStyles = new FILLSTYLE[1]; - FILLSTYLE fillStyle = new FILLSTYLE(); - fillStyle.fillStyleType = Configuration.shapeImportUseNonSmoothedFill.get() - ? FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP : FILLSTYLE.REPEATING_BITMAP; - fillStyle.bitmapId = getCharacterId(); - MATRIX matrix = new MATRIX(); - matrix.hasScale = true; - if (fill) { - RECT imageRect = getRect(); - matrix.scaleX = (int) ((((long) SWF.unitDivisor) << 16) * rect.getWidth() / imageRect.getWidth()); - matrix.scaleY = (int) ((((long) SWF.unitDivisor) << 16) * rect.getHeight() / imageRect.getHeight()); - } else { - matrix.scaleX = ((int) SWF.unitDivisor) << 16; - matrix.scaleY = matrix.scaleX; - } - if (translated) { - matrix.translateX = rect.Xmin; - matrix.translateY = rect.Ymin; - } - fillStyle.bitmapMatrix = matrix; - shape.fillStyles.fillStyles[0] = fillStyle; - - shape.lineStyles = new LINESTYLEARRAY(); - shape.lineStyles.lineStyles = new LINESTYLE[0]; - shape.shapeRecords = new ArrayList<>(); - StyleChangeRecord style = new StyleChangeRecord(); - style.stateFillStyle0 = true; - style.fillStyle0 = 1; - style.stateMoveTo = true; - if (translated) { - style.moveDeltaX = rect.Xmin; - style.moveDeltaY = rect.Ymin; - } - shape.shapeRecords.add(style); - StraightEdgeRecord top = new StraightEdgeRecord(); - top.generalLineFlag = true; - top.deltaX = rect.getWidth(); - StraightEdgeRecord right = new StraightEdgeRecord(); - right.generalLineFlag = true; - right.deltaY = rect.getHeight(); - StraightEdgeRecord bottom = new StraightEdgeRecord(); - bottom.generalLineFlag = true; - bottom.deltaX = -rect.getWidth(); - StraightEdgeRecord left = new StraightEdgeRecord(); - left.generalLineFlag = true; - left.deltaY = -rect.getHeight(); - shape.shapeRecords.add(top); - shape.shapeRecords.add(right); - shape.shapeRecords.add(bottom); - shape.shapeRecords.add(left); - shape.shapeRecords.add(new EndShapeRecord()); - return shape; - } - - @Override - public RECT getRect() { - return getRect(null); // parameter not used - } - - @Override - public RECT getRect(Set added) { - Dimension dimension = getImageDimension(); - int widthInTwips = (int) (dimension.getWidth() * SWF.unitDivisor); - int heightInTwips = (int) (dimension.getHeight() * SWF.unitDivisor); - return new RECT(0, widthInTwips, 0, heightInTwips); - } - - @Override - public int getUsedParameters() { - return 0; - } - - @Override - public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) { - return transformation.toTransform().createTransformedShape(getShape().getOutline(swf, stroked)); - } - - @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) { - BitmapExporter.export(swf, getShape(), null, image, transformation, strokeTransformation, colorTransform); - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException { - SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShape(), exporter, null, colorTransform, 1); - shapeExporter.export(); - } - - @Override - public void toHtmlCanvas(StringBuilder result, double unitDivisor) { - CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShape(), null, 0, 0); - cse.export(); - result.append(cse.getShapeData()); - } - - @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } - - public void clearCache() { - cachedImage = null; - } - - @Override - public void getTagInfo(TagInfo tagInfo) { - super.getTagInfo(tagInfo); - Dimension dimension = getImageDimension(); - tagInfo.addInfo("general", "width", dimension.getWidth()); - tagInfo.addInfo("general", "height", dimension.getHeight()); - } - - @Override - public int getCharacterId() { - return characterID; - } - - @Override - public void setCharacterId(int characterId) { - this.characterID = characterId; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags.base; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; +import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; +import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; +import com.jpexs.decompiler.flash.helpers.ImageHelper; +import com.jpexs.decompiler.flash.tags.TagInfo; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.FILLSTYLE; +import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.LINESTYLE; +import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import java.awt.Dimension; +import java.awt.Shape; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Set; + +/** + * + * @author JPEXS + */ +public abstract class ImageTag extends DrawableTag { + + @SWFType(BasicType.UI16) + public int characterID; + + protected SerializableImage cachedImage; + + public ImageTag(SWF swf, int id, String name, ByteArrayRange data) { + super(swf, id, name, data); + } + + public abstract InputStream getOriginalImageData(); + + protected abstract SerializableImage getImage(); + + public abstract Dimension getImageDimension(); + + public abstract void setImage(byte[] data) throws IOException; + + public abstract ImageFormat getImageFormat(); + + public abstract ImageFormat getOriginalImageFormat(); + + public boolean importSupported() { + return true; + } + + public static ImageFormat getImageFormat(byte[] data) { + return getImageFormat(new ByteArrayRange(data)); + } + + public static ImageFormat getImageFormat(ByteArrayRange data) { + if (hasErrorHeader(data)) { + return ImageFormat.JPEG; + } + + if (data.getLength() > 2 && ((data.get(0) & 0xff) == 0xff) && ((data.get(1) & 0xff) == 0xd8)) { + return ImageFormat.JPEG; + } + + if (data.getLength() > 6 && ((data.get(0) & 0xff) == 0x47) && ((data.get(1) & 0xff) == 0x49) && ((data.get(2) & 0xff) == 0x46) && ((data.get(3) & 0xff) == 0x38) && ((data.get(4) & 0xff) == 0x39) && ((data.get(5) & 0xff) == 0x61)) { + return ImageFormat.GIF; + } + + if (data.getLength() > 8 && ((data.get(0) & 0xff) == 0x89) && ((data.get(1) & 0xff) == 0x50) && ((data.get(2) & 0xff) == 0x4e) && ((data.get(3) & 0xff) == 0x47) && ((data.get(4) & 0xff) == 0x0d) && ((data.get(5) & 0xff) == 0x0a) && ((data.get(6) & 0xff) == 0x1a) && ((data.get(7) & 0xff) == 0x0a)) { + return ImageFormat.PNG; + } + + return ImageFormat.UNKNOWN; + } + + public SerializableImage getImageCached() { + if (cachedImage != null) { + return cachedImage; + } + + SerializableImage image = getImage(); + if (Configuration.cacheImages.get()) { + cachedImage = image; + } + + return image; + } + + public InputStream getImageData() { + InputStream is = getOriginalImageData(); + if (is != null) { + return is; + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageHelper.write(getImage().getBufferedImage(), getImageFormat(), baos); + return new ByteArrayInputStream(baos.toByteArray()); + } + + public static boolean hasErrorHeader(byte[] data) { + return hasErrorHeader(new ByteArrayRange(data)); + } + + public static boolean hasErrorHeader(ByteArrayRange data) { + if (data.getLength() > 4) { + if ((data.get(0) & 0xff) == 0xff && (data.get(1) & 0xff) == 0xd9 + && (data.get(2) & 0xff) == 0xff && (data.get(3) & 0xff) == 0xd8) { + return true; + } + } + return false; + } + + private SHAPEWITHSTYLE getShape() { + RECT rect = getRect(); + return getShape(rect, false); + } + + public SHAPEWITHSTYLE getShape(RECT rect, boolean fill) { + boolean translated = rect.Xmin != 0 || rect.Ymin != 0; + SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE(); + shape.fillStyles = new FILLSTYLEARRAY(); + shape.fillStyles.fillStyles = new FILLSTYLE[1]; + FILLSTYLE fillStyle = new FILLSTYLE(); + fillStyle.fillStyleType = Configuration.shapeImportUseNonSmoothedFill.get() + ? FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP : FILLSTYLE.REPEATING_BITMAP; + fillStyle.bitmapId = getCharacterId(); + MATRIX matrix = new MATRIX(); + matrix.hasScale = true; + if (fill) { + RECT imageRect = getRect(); + matrix.scaleX = (int) ((((long) SWF.unitDivisor) << 16) * rect.getWidth() / imageRect.getWidth()); + matrix.scaleY = (int) ((((long) SWF.unitDivisor) << 16) * rect.getHeight() / imageRect.getHeight()); + } else { + matrix.scaleX = ((int) SWF.unitDivisor) << 16; + matrix.scaleY = matrix.scaleX; + } + if (translated) { + matrix.translateX = rect.Xmin; + matrix.translateY = rect.Ymin; + } + fillStyle.bitmapMatrix = matrix; + shape.fillStyles.fillStyles[0] = fillStyle; + + shape.lineStyles = new LINESTYLEARRAY(); + shape.lineStyles.lineStyles = new LINESTYLE[0]; + shape.shapeRecords = new ArrayList<>(); + StyleChangeRecord style = new StyleChangeRecord(); + style.stateFillStyle0 = true; + style.fillStyle0 = 1; + style.stateMoveTo = true; + if (translated) { + style.moveDeltaX = rect.Xmin; + style.moveDeltaY = rect.Ymin; + } + shape.shapeRecords.add(style); + StraightEdgeRecord top = new StraightEdgeRecord(); + top.generalLineFlag = true; + top.deltaX = rect.getWidth(); + StraightEdgeRecord right = new StraightEdgeRecord(); + right.generalLineFlag = true; + right.deltaY = rect.getHeight(); + StraightEdgeRecord bottom = new StraightEdgeRecord(); + bottom.generalLineFlag = true; + bottom.deltaX = -rect.getWidth(); + StraightEdgeRecord left = new StraightEdgeRecord(); + left.generalLineFlag = true; + left.deltaY = -rect.getHeight(); + shape.shapeRecords.add(top); + shape.shapeRecords.add(right); + shape.shapeRecords.add(bottom); + shape.shapeRecords.add(left); + shape.shapeRecords.add(new EndShapeRecord()); + return shape; + } + + @Override + public RECT getRect() { + return getRect(null); // parameter not used + } + + @Override + public RECT getRect(Set added) { + Dimension dimension = getImageDimension(); + int widthInTwips = (int) (dimension.getWidth() * SWF.unitDivisor); + int heightInTwips = (int) (dimension.getHeight() * SWF.unitDivisor); + return new RECT(0, widthInTwips, 0, heightInTwips); + } + + @Override + public int getUsedParameters() { + return 0; + } + + @Override + public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) { + return transformation.toTransform().createTransformedShape(getShape().getOutline(swf, stroked)); + } + + @Override + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) { + BitmapExporter.export(swf, getShape(), null, image, transformation, strokeTransformation, colorTransform); + } + + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException { + SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShape(), exporter, null, colorTransform, 1); + shapeExporter.export(); + } + + @Override + public void toHtmlCanvas(StringBuilder result, double unitDivisor) { + CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShape(), null, 0, 0); + cse.export(); + result.append(cse.getShapeData()); + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + return true; + } + + public void clearCache() { + cachedImage = null; + } + + @Override + public void getTagInfo(TagInfo tagInfo) { + super.getTagInfo(tagInfo); + Dimension dimension = getImageDimension(); + tagInfo.addInfo("general", "width", dimension.getWidth()); + tagInfo.addInfo("general", "height", dimension.getHeight()); + } + + @Override + public int getCharacterId() { + return characterID; + } + + @Override + public void setCharacterId(int characterId) { + this.characterID = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java index 172e5e810..781e37869 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java @@ -1,52 +1,52 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.types; - -import com.jpexs.decompiler.flash.tags.DefineShape3Tag; -import com.jpexs.decompiler.flash.tags.DefineShape4Tag; -import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; -import com.jpexs.decompiler.flash.types.annotations.ConditionalType; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import java.io.Serializable; -import java.util.Set; - -/** - * - * @author JPEXS - */ -public class LINESTYLE implements NeedsCharacters, Serializable { - - @SWFType(BasicType.UI16) - public int width; - - @ConditionalType(tags = {DefineShape3Tag.ID, DefineShape4Tag.ID}, type = RGBA.class) - public RGB color; - - @Override - public void getNeededCharacters(Set needed) { - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - return false; - } - - @Override - public boolean removeCharacter(int characterId) { - return false; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.types; + +import com.jpexs.decompiler.flash.tags.DefineShape3Tag; +import com.jpexs.decompiler.flash.tags.DefineShape4Tag; +import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; +import com.jpexs.decompiler.flash.types.annotations.ConditionalType; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import java.io.Serializable; +import java.util.Set; + +/** + * + * @author JPEXS + */ +public class LINESTYLE implements NeedsCharacters, Serializable { + + @SWFType(BasicType.UI16) + public int width; + + @ConditionalType(tags = {DefineShape3Tag.ID, DefineShape4Tag.ID}, type = RGBA.class) + public RGB color; + + @Override + public void getNeededCharacters(Set needed) { + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + + @Override + public boolean removeCharacter(int characterId) { + return false; + } +} diff --git a/libsrc/ffdec_lib/testdata/as3/as3.html b/libsrc/ffdec_lib/testdata/as3/as3.html index 8b3feba2a..2cb16b28d 100644 --- a/libsrc/ffdec_lib/testdata/as3/as3.html +++ b/libsrc/ffdec_lib/testdata/as3/as3.html @@ -1,49 +1,49 @@ - - - - as3 - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - Get Adobe Flash player - - - - - -
- - + + + + as3 + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + Get Adobe Flash player + + + + + +
+ + diff --git a/nbproject/ide-targets.xml b/nbproject/ide-targets.xml index ab8db7552..6ef055fbd 100644 --- a/nbproject/ide-targets.xml +++ b/nbproject/ide-targets.xml @@ -1,33 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/jpexs/decompiler/flash/gui/AdvancedSettingsDialog.java b/src/com/jpexs/decompiler/flash/gui/AdvancedSettingsDialog.java index d639549cc..13e065347 100644 --- a/src/com/jpexs/decompiler/flash/gui/AdvancedSettingsDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/AdvancedSettingsDialog.java @@ -1,631 +1,631 @@ -/* - * Copyright (C) 2010-2016 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.configuration.Configuration; -import com.jpexs.decompiler.flash.configuration.ConfigurationCategory; -import com.jpexs.decompiler.flash.configuration.ConfigurationDirectory; -import com.jpexs.decompiler.flash.configuration.ConfigurationFile; -import com.jpexs.decompiler.flash.configuration.ConfigurationInternal; -import com.jpexs.decompiler.flash.configuration.ConfigurationItem; -import com.jpexs.decompiler.flash.gui.helpers.SpringUtilities; -import com.jpexs.helpers.Helper; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Insets; -import java.awt.RenderingHints; -import java.awt.event.ActionEvent; -import java.io.File; -import java.lang.reflect.Field; -import java.lang.reflect.ParameterizedType; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collections; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.Icon; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTabbedPane; -import javax.swing.JTextField; -import javax.swing.SpringLayout; -import javax.swing.WindowConstants; -import javax.swing.filechooser.FileFilter; -import javax.swing.table.DefaultTableModel; -import org.pushingpixels.substance.api.ColorSchemeAssociationKind; -import org.pushingpixels.substance.api.ComponentState; -import org.pushingpixels.substance.api.DecorationAreaType; -import org.pushingpixels.substance.api.SubstanceLookAndFeel; -import org.pushingpixels.substance.api.SubstanceSkin; -import org.pushingpixels.substance.api.renderers.SubstanceDefaultListCellRenderer; -import org.pushingpixels.substance.api.skin.SkinInfo; - -/** - * - * @author JPEXS - */ -public class AdvancedSettingsDialog extends AppDialog { - - private final Map componentsMap = new HashMap<>(); - - private JButton cancelButton; - - private JButton okButton; - - private JButton resetButton; - - /** - * Creates new form AdvancedSettingsDialog - * - * @param selectedCategory - */ - public AdvancedSettingsDialog(String selectedCategory) { - initComponents(selectedCategory); - View.centerScreen(this); - View.setWindowIcon(this); - - //configurationTable.setCellEditor(configurationTable.getDefaultEditor(null)); - pack(); - } - - private DefaultTableModel getModel() { - return new DefaultTableModel( - new Object[][]{}, - new String[]{ - translate("advancedSettings.columns.name"), - translate("advancedSettings.columns.value"), - translate("advancedSettings.columns.description") - } - ) { - Class[] types = new Class[]{ - String.class, Object.class, String.class - }; - - boolean[] canEdit = new boolean[]{ - false, true, false - }; - - @Override - public Class getColumnClass(int columnIndex) { - return types[columnIndex]; - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - return canEdit[columnIndex]; - } - }; - } - - private static class SkinSelect { - - private final String name; - - private final String className; - - public SkinSelect(String name, String className) { - this.name = name; - this.className = className; - } - - public String getClassName() { - return className; - } - - @Override - public String toString() { - return name; - } - } - - private void initComponents(String selectedCategory) { - okButton = new JButton(); - cancelButton = new JButton(); - resetButton = new JButton(); - - setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - setTitle(translate("advancedSettings.dialog.title")); - setModal(true); - setPreferredSize(new Dimension(800, 500)); - - okButton.setText(AppStrings.translate("button.ok")); - okButton.addActionListener(this::okButtonActionPerformed); - - cancelButton.setText(AppStrings.translate("button.cancel")); - cancelButton.addActionListener(this::cancelButtonActionPerformed); - - resetButton.setText(AppStrings.translate("button.reset")); - resetButton.addActionListener(this::resetButtonActionPerformed); - - Container cnt = getContentPane(); - cnt.setLayout(new BorderLayout()); - //cnt.add(new JScrollPane(configurationTable),BorderLayout.CENTER); - - JPanel buttonsPanel = new JPanel(new BorderLayout()); - - JPanel buttonsLeftPanel = new JPanel(new FlowLayout()); - buttonsLeftPanel.add(resetButton, BorderLayout.WEST); - - buttonsPanel.add(buttonsLeftPanel, BorderLayout.WEST); - - JPanel buttonsRightPanel = new JPanel(new FlowLayout()); - buttonsRightPanel.add(cancelButton); - buttonsRightPanel.add(okButton); - buttonsPanel.add(buttonsRightPanel, BorderLayout.EAST); - - cnt.add(buttonsPanel, BorderLayout.SOUTH); - - JTabbedPane tabPane = new JTabbedPane(); - - JComboBox skinComboBox = new JComboBox<>(); - skinComboBox.setRenderer(new SubstanceDefaultListCellRenderer() { - - @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - SubstanceDefaultListCellRenderer cmp = (SubstanceDefaultListCellRenderer) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); //To change body of generated methods, choose Tools | Templates. - final SkinSelect ss = (SkinSelect) value; - cmp.setIcon(new Icon() { - - @Override - public void paintIcon(Component c, Graphics g, int x, int y) { - Graphics2D g2 = (Graphics2D) g; - g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); - g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - try { - Class act = Class.forName(ss.getClassName()); - SubstanceSkin skin = (SubstanceSkin) act.newInstance(); - Color fill = skin.getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.FILL, ComponentState.ENABLED).getBackgroundFillColor(); - Color hilight = skin.getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.FILL, ComponentState.ROLLOVER_SELECTED).getBackgroundFillColor(); - Color border = skin.getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.BORDER, ComponentState.ENABLED).getDarkColor(); - g2.setColor(fill); - g2.fillOval(0, 0, 16, 16); - g2.setColor(hilight); - g2.fillArc(0, 0, 16, 16, -45, 90); - g2.setColor(border); - g2.drawOval(0, 0, 16, 16); - - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) { - //no icon - } - - } - - @Override - public int getIconWidth() { - return 16; - } - - @Override - public int getIconHeight() { - return 16; - } - }); - return cmp; - } - - }); - skinComboBox.addItem(new SkinSelect(OceanicSkin.NAME, OceanicSkin.class.getName())); - Map skins = SubstanceLookAndFeel.getAllSkins(); - for (String skinKey : skins.keySet()) { - SkinInfo skin = skins.get(skinKey); - skinComboBox.addItem(new SkinSelect(skin.getDisplayName(), skin.getClassName())); - if (skin.getClassName().equals(Configuration.guiSkin.get())) { - skinComboBox.setSelectedIndex(skinComboBox.getItemCount() - 1); - } - } - - Map tabs = new HashMap<>(); - getCategories(componentsMap, tabs, skinComboBox, getResourceBundle()); - - String catOrder[] = new String[]{"ui", "display", "decompilation", "script", "format", "export", "import", "paths", "limit", "update", "debug", "other"}; - - for (String cat : catOrder) { - if (!tabs.containsKey(cat)) { - continue; - } - - tabPane.add(translate("config.group.name." + cat), tabs.get(cat)); - tabPane.setToolTipTextAt(tabPane.getTabCount() - 1, translate("config.group.description." + cat)); - } - if (selectedCategory != null && tabs.containsKey(selectedCategory)) { - tabPane.setSelectedComponent(tabs.get(selectedCategory)); - } - - cnt.add(tabPane, BorderLayout.CENTER); - pack(); - } - - public static String selectConfigFile(ConfigurationItem config, String current, String pattern) { - JFileChooser fc = new JFileChooser(); - fc.setSelectedFile(new File(current)); - fc.setMultiSelectionEnabled(false); - fc.setCurrentDirectory(new File((String) config.get())); - FileFilter allSupportedFilter = new FileFilter() { - private final String[] supportedExtensions = new String[]{".swf", ".gfx", ".swc", ".zip"}; - - @Override - public boolean accept(File f) { - if (f.isDirectory()) { - return true; - } - return f.getName().matches(pattern); - } - - @Override - public String getDescription() { - return ""; - } - }; - fc.setFileFilter(allSupportedFilter); - - fc.setAcceptAllFileFilterUsed(false); - JFrame f = new JFrame(); - View.setWindowIcon(f); - int returnVal = fc.showOpenDialog(f); - if (returnVal == JFileChooser.APPROVE_OPTION) { - return Helper.fixDialogFile(fc.getSelectedFile()).getAbsolutePath(); - } else { - return (String) config.get(); - } - } - - public static void getCategories(Map componentsMap, Map tabs, JComboBox skinComboBox, ResourceBundle resourceBundle) { - Map> categorized = new HashMap<>(); - - Map fields = Configuration.getConfigurationFields(); - String[] keys = new String[fields.size()]; - keys = fields.keySet().toArray(keys); - Arrays.sort(keys); - - for (String name : keys) { - Field field = fields.get(name); - ConfigurationCategory cat = field.getAnnotation(ConfigurationCategory.class); - String scat = (cat == null || cat.value().isEmpty()) ? "other" : cat.value(); - if (!categorized.containsKey(scat)) { - categorized.put(scat, new HashMap<>()); - } - - categorized.get(scat).put(name, field); - } - - for (String cat : categorized.keySet()) { - JPanel configPanel = new JPanel(new SpringLayout()); - int itemCount = 0; - List names = new ArrayList<>(categorized.get(cat).keySet()); - - final Map locNames = new HashMap<>(); - for (String name : names) { - String locName; - - if (resourceBundle.containsKey("config.name." + name)) { - locName = resourceBundle.getString("config.name." + name); - } else { //if it is undocumented, then it must have ConfigurationInternal annotation - Field f = fields.get(name); - ConfigurationInternal cint = f.getAnnotation(ConfigurationInternal.class); - if (cint == null) { - throw new RuntimeException("Missing configuration name: " + name); - } - - locName = "(Internal) " + name; - } - - locNames.put(name, locName); - } - - Collections.sort(names, new Comparator() { - @Override - public int compare(String name1, String name2) { - return locNames.get(name1).compareTo(locNames.get(name2)); - } - }); - for (String name : names) { - Field field = categorized.get(cat).get(name); - - String locName = locNames.get(name); - - try { - ConfigurationItem item = (ConfigurationItem) field.get(null); - - ParameterizedType listType = (ParameterizedType) field.getGenericType(); - java.lang.reflect.Type itemType2 = listType.getActualTypeArguments()[0]; - if (!(itemType2 instanceof Class)) { - continue; - } - - Class itemType = (Class) itemType2; - - String description = ""; - if (resourceBundle.containsKey("config.description." + name)) { - description = resourceBundle.getString("config.description." + name); - } - - Object defaultValue = Configuration.getDefaultValue(field); - if (name.equals("gui.skin")) { - Class c; - try { - c = Class.forName((String) defaultValue); - defaultValue = c.getField("NAME").get(c); - } catch (ClassNotFoundException | NoSuchFieldException | SecurityException ex) { - Logger.getLogger(AdvancedSettingsDialog.class.getName()).log(Level.SEVERE, null, ex); - } - } - - if (defaultValue != null) { - description += " (" + resourceBundle.getString("default") + ": " + defaultValue + ")"; - } - - JLabel l = new JLabel(locName, JLabel.TRAILING); - l.setToolTipText(description); - configPanel.add(l); - Component c = null; - Component addComponent = null; - if (name.equals("gui.skin")) { - skinComboBox.setToolTipText(description); - skinComboBox.setMaximumSize(new Dimension(Integer.MAX_VALUE, skinComboBox.getPreferredSize().height)); - c = skinComboBox; - } else if ((itemType == String.class) || (itemType == Integer.class) || (itemType == Long.class) || (itemType == Double.class) || (itemType == Float.class) || (itemType == Calendar.class)) { - ConfigurationFile confFile = field.getAnnotation(ConfigurationFile.class); - ConfigurationDirectory confDirectory = field.getAnnotation(ConfigurationDirectory.class); - - JTextField tf = new JTextField(); - Object val = item.get(); - if (val == null) { - val = ""; - } - if (itemType == Calendar.class) { - tf.setText(new SimpleDateFormat().format(((Calendar) val).getTime())); - } else { - tf.setText(val.toString()); - } - tf.setToolTipText(description); - tf.setMaximumSize(new Dimension(Integer.MAX_VALUE, tf.getPreferredSize().height)); - - c = tf; - if (confFile != null) { //|| confDirectory != null) { - JPanel p = new JPanel(new BorderLayout()); - p.setMaximumSize(new Dimension(Integer.MAX_VALUE, tf.getPreferredSize().height)); - p.add(tf, BorderLayout.CENTER); - JButton butSelect = new JButton(View.getIcon("folderopen16")); - butSelect.setToolTipText(ResourceBundle.getBundle(AppStrings.getResourcePath(MainFrame.class)).getString("FileChooser.openButtonText")); - butSelect.setMargin(new Insets(2, 2, 2, 2)); - butSelect.addActionListener((ActionEvent e) -> { - tf.setText(selectConfigFile(item, tf.getText(), confFile.value())); - }); - p.add(butSelect, BorderLayout.EAST); - addComponent = p; - } - } else if (itemType == Boolean.class) { - JCheckBox cb = new JCheckBox(); - cb.setSelected((Boolean) item.get()); - cb.setToolTipText(description); - c = cb; - } else if (itemType.isEnum()) { - JComboBox cb = new JComboBox<>(); - @SuppressWarnings("unchecked") - EnumSet enumValues = EnumSet.allOf(itemType); - String stringValue = null; - for (Object enumValue : enumValues) { - String enumValueStr = enumValue.toString(); - if (stringValue == null) { - stringValue = enumValueStr; - } - cb.addItem(enumValueStr); - } - if (item.get() != null) { - stringValue = item.get().toString(); - } - cb.setToolTipText(description); - cb.setSelectedItem(stringValue); - cb.setMaximumSize(new Dimension(Integer.MAX_VALUE, cb.getPreferredSize().height)); - c = cb; - } else { - throw new UnsupportedOperationException("Configuration ttem type '" + itemType.getName() + "' is not supported"); - } - - componentsMap.put(name, c); - if (addComponent == null) { - addComponent = c; - } - l.setLabelFor(c); - configPanel.add(addComponent); - } catch (IllegalArgumentException | IllegalAccessException ex) { - // Reflection exceptions. This should never happen - throw new Error(ex.getMessage()); - } - - itemCount++; - } - - SpringUtilities.makeCompactGrid(configPanel, - itemCount, 2, //rows, cols - 6, 6, //initX, initY - 6, 6); //xPad, yPad - //https://www.adobe.com/support/flashplayer/debug_downloads.html - if (resourceBundle.containsKey("config.group.tip." + cat)) { - String tip = resourceBundle.getString("config.group.tip." + cat); - String url = null; - if (resourceBundle.containsKey("config.group.link." + cat)) { - url = resourceBundle.getString("config.group.link." + cat); - } - JPanel p = new JPanel(new BorderLayout()); - p.add(configPanel, BorderLayout.CENTER); - JPanel tipPanel = new JPanel(new FlowLayout()); - tipPanel.add(new JLabel("" + resourceBundle.getString("tip") + "" + tip + "")); - if (url != null) { - String linkText = url; - if (resourceBundle.containsKey("config.group.linkText." + cat)) { - linkText = resourceBundle.getString("config.group.linkText." + cat); - } - tipPanel.add(new LinkLabel(linkText, url)); - } - p.add(tipPanel, BorderLayout.SOUTH); - configPanel = p; - } - tabs.put(cat, new JScrollPane(configPanel)); - } - } - - private void showRestartConfirmDialod() { - if (View.showConfirmDialog(this, translate("advancedSettings.restartConfirmation"), AppStrings.translate("message.warning"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { - View.execInEventDispatchLater(() -> { - try { - Thread.sleep(1000); - } catch (InterruptedException ex) { - Logger.getLogger(AdvancedSettingsDialog.class.getName()).log(Level.SEVERE, null, ex); - } - SelectLanguageDialog.reloadUi(); - }); - - } - } - - @SuppressWarnings("unchecked") - private void okButtonActionPerformed(ActionEvent evt) { - boolean modified = false; - Map fields = Configuration.getConfigurationFields(); - Map values = new HashMap<>(); - for (String name : fields.keySet()) { - Component c = componentsMap.get(name); - Object value = null; - - ParameterizedType listType = (ParameterizedType) fields.get(name).getGenericType(); - java.lang.reflect.Type itemType2 = listType.getActualTypeArguments()[0]; - if (!(itemType2 instanceof Class)) { - continue; - } - - Class itemType = (Class) itemType2; - if (name.equals("gui.skin")) { - value = ((SkinSelect) ((JComboBox) c).getSelectedItem()).className; - } else if (itemType == String.class) { - value = ((JTextField) c).getText(); - } - if (itemType == Boolean.class) { - value = ((JCheckBox) c).isSelected(); - } - - if (itemType == Calendar.class) { - Calendar cal = Calendar.getInstance(); - try { - cal.setTime(new SimpleDateFormat().parse(((JTextField) c).getText())); - } catch (ParseException ex) { - c.requestFocusInWindow(); - return; - } - value = cal; - } - - if (itemType.isEnum()) { - String stringValue = (String) ((JComboBox) c).getSelectedItem(); - value = Enum.valueOf(itemType, stringValue); - } - - try { - if (itemType == Integer.class) { - value = Integer.parseInt(((JTextField) c).getText()); - } - if (itemType == Long.class) { - value = Long.parseLong(((JTextField) c).getText()); - } - if (itemType == Double.class) { - value = Double.parseDouble(((JTextField) c).getText()); - } - if (itemType == Float.class) { - value = Float.parseFloat(((JTextField) c).getText()); - } - } catch (NumberFormatException nfe) { - if (!((JTextField) c).getText().isEmpty()) { - c.requestFocusInWindow(); - return; - } // else null - } - values.put(name, value); - } - - for (String name : fields.keySet()) { - Component c = componentsMap.get(name); - Object value = values.get(name); - - Field field = fields.get(name); - ConfigurationItem item = null; - try { - item = (ConfigurationItem) field.get(null); - } catch (IllegalArgumentException | IllegalAccessException ex) { - // Reflection exceptions. This should never happen - throw new Error(ex.getMessage()); - } - if (item.get() == null || !item.get().equals(value)) { - if (item.hasValue() || value != null) { - item.set(value); - modified = true; - } - } - } - Configuration.saveConfig(); - setVisible(false); - if (modified) { - showRestartConfirmDialod(); - } - } - - private void cancelButtonActionPerformed(ActionEvent evt) { - setVisible(false); - } - - private void resetButtonActionPerformed(ActionEvent evt) { - Map rfields = Configuration.getConfigurationFields(); - for (Entry entry : rfields.entrySet()) { - String name = entry.getKey(); - Field field = entry.getValue(); - try { - ConfigurationItem item = (ConfigurationItem) field.get(null); - item.unset(); - } catch (IllegalArgumentException | IllegalAccessException ex) { - // Reflection exceptions. This should never happen - throw new Error(ex.getMessage()); - } - } - Configuration.saveConfig(); - setVisible(false); - showRestartConfirmDialod(); - } -} +/* + * Copyright (C) 2010-2016 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.configuration.Configuration; +import com.jpexs.decompiler.flash.configuration.ConfigurationCategory; +import com.jpexs.decompiler.flash.configuration.ConfigurationDirectory; +import com.jpexs.decompiler.flash.configuration.ConfigurationFile; +import com.jpexs.decompiler.flash.configuration.ConfigurationInternal; +import com.jpexs.decompiler.flash.configuration.ConfigurationItem; +import com.jpexs.decompiler.flash.gui.helpers.SpringUtilities; +import com.jpexs.helpers.Helper; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.ResourceBundle; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; +import javax.swing.SpringLayout; +import javax.swing.WindowConstants; +import javax.swing.filechooser.FileFilter; +import javax.swing.table.DefaultTableModel; +import org.pushingpixels.substance.api.ColorSchemeAssociationKind; +import org.pushingpixels.substance.api.ComponentState; +import org.pushingpixels.substance.api.DecorationAreaType; +import org.pushingpixels.substance.api.SubstanceLookAndFeel; +import org.pushingpixels.substance.api.SubstanceSkin; +import org.pushingpixels.substance.api.renderers.SubstanceDefaultListCellRenderer; +import org.pushingpixels.substance.api.skin.SkinInfo; + +/** + * + * @author JPEXS + */ +public class AdvancedSettingsDialog extends AppDialog { + + private final Map componentsMap = new HashMap<>(); + + private JButton cancelButton; + + private JButton okButton; + + private JButton resetButton; + + /** + * Creates new form AdvancedSettingsDialog + * + * @param selectedCategory + */ + public AdvancedSettingsDialog(String selectedCategory) { + initComponents(selectedCategory); + View.centerScreen(this); + View.setWindowIcon(this); + + //configurationTable.setCellEditor(configurationTable.getDefaultEditor(null)); + pack(); + } + + private DefaultTableModel getModel() { + return new DefaultTableModel( + new Object[][]{}, + new String[]{ + translate("advancedSettings.columns.name"), + translate("advancedSettings.columns.value"), + translate("advancedSettings.columns.description") + } + ) { + Class[] types = new Class[]{ + String.class, Object.class, String.class + }; + + boolean[] canEdit = new boolean[]{ + false, true, false + }; + + @Override + public Class getColumnClass(int columnIndex) { + return types[columnIndex]; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return canEdit[columnIndex]; + } + }; + } + + private static class SkinSelect { + + private final String name; + + private final String className; + + public SkinSelect(String name, String className) { + this.name = name; + this.className = className; + } + + public String getClassName() { + return className; + } + + @Override + public String toString() { + return name; + } + } + + private void initComponents(String selectedCategory) { + okButton = new JButton(); + cancelButton = new JButton(); + resetButton = new JButton(); + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + setTitle(translate("advancedSettings.dialog.title")); + setModal(true); + setPreferredSize(new Dimension(800, 500)); + + okButton.setText(AppStrings.translate("button.ok")); + okButton.addActionListener(this::okButtonActionPerformed); + + cancelButton.setText(AppStrings.translate("button.cancel")); + cancelButton.addActionListener(this::cancelButtonActionPerformed); + + resetButton.setText(AppStrings.translate("button.reset")); + resetButton.addActionListener(this::resetButtonActionPerformed); + + Container cnt = getContentPane(); + cnt.setLayout(new BorderLayout()); + //cnt.add(new JScrollPane(configurationTable),BorderLayout.CENTER); + + JPanel buttonsPanel = new JPanel(new BorderLayout()); + + JPanel buttonsLeftPanel = new JPanel(new FlowLayout()); + buttonsLeftPanel.add(resetButton, BorderLayout.WEST); + + buttonsPanel.add(buttonsLeftPanel, BorderLayout.WEST); + + JPanel buttonsRightPanel = new JPanel(new FlowLayout()); + buttonsRightPanel.add(cancelButton); + buttonsRightPanel.add(okButton); + buttonsPanel.add(buttonsRightPanel, BorderLayout.EAST); + + cnt.add(buttonsPanel, BorderLayout.SOUTH); + + JTabbedPane tabPane = new JTabbedPane(); + + JComboBox skinComboBox = new JComboBox<>(); + skinComboBox.setRenderer(new SubstanceDefaultListCellRenderer() { + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + SubstanceDefaultListCellRenderer cmp = (SubstanceDefaultListCellRenderer) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); //To change body of generated methods, choose Tools | Templates. + final SkinSelect ss = (SkinSelect) value; + cmp.setIcon(new Icon() { + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + try { + Class act = Class.forName(ss.getClassName()); + SubstanceSkin skin = (SubstanceSkin) act.newInstance(); + Color fill = skin.getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.FILL, ComponentState.ENABLED).getBackgroundFillColor(); + Color hilight = skin.getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.FILL, ComponentState.ROLLOVER_SELECTED).getBackgroundFillColor(); + Color border = skin.getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.BORDER, ComponentState.ENABLED).getDarkColor(); + g2.setColor(fill); + g2.fillOval(0, 0, 16, 16); + g2.setColor(hilight); + g2.fillArc(0, 0, 16, 16, -45, 90); + g2.setColor(border); + g2.drawOval(0, 0, 16, 16); + + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) { + //no icon + } + + } + + @Override + public int getIconWidth() { + return 16; + } + + @Override + public int getIconHeight() { + return 16; + } + }); + return cmp; + } + + }); + skinComboBox.addItem(new SkinSelect(OceanicSkin.NAME, OceanicSkin.class.getName())); + Map skins = SubstanceLookAndFeel.getAllSkins(); + for (String skinKey : skins.keySet()) { + SkinInfo skin = skins.get(skinKey); + skinComboBox.addItem(new SkinSelect(skin.getDisplayName(), skin.getClassName())); + if (skin.getClassName().equals(Configuration.guiSkin.get())) { + skinComboBox.setSelectedIndex(skinComboBox.getItemCount() - 1); + } + } + + Map tabs = new HashMap<>(); + getCategories(componentsMap, tabs, skinComboBox, getResourceBundle()); + + String catOrder[] = new String[]{"ui", "display", "decompilation", "script", "format", "export", "import", "paths", "limit", "update", "debug", "other"}; + + for (String cat : catOrder) { + if (!tabs.containsKey(cat)) { + continue; + } + + tabPane.add(translate("config.group.name." + cat), tabs.get(cat)); + tabPane.setToolTipTextAt(tabPane.getTabCount() - 1, translate("config.group.description." + cat)); + } + if (selectedCategory != null && tabs.containsKey(selectedCategory)) { + tabPane.setSelectedComponent(tabs.get(selectedCategory)); + } + + cnt.add(tabPane, BorderLayout.CENTER); + pack(); + } + + public static String selectConfigFile(ConfigurationItem config, String current, String pattern) { + JFileChooser fc = new JFileChooser(); + fc.setSelectedFile(new File(current)); + fc.setMultiSelectionEnabled(false); + fc.setCurrentDirectory(new File((String) config.get())); + FileFilter allSupportedFilter = new FileFilter() { + private final String[] supportedExtensions = new String[]{".swf", ".gfx", ".swc", ".zip"}; + + @Override + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + return f.getName().matches(pattern); + } + + @Override + public String getDescription() { + return ""; + } + }; + fc.setFileFilter(allSupportedFilter); + + fc.setAcceptAllFileFilterUsed(false); + JFrame f = new JFrame(); + View.setWindowIcon(f); + int returnVal = fc.showOpenDialog(f); + if (returnVal == JFileChooser.APPROVE_OPTION) { + return Helper.fixDialogFile(fc.getSelectedFile()).getAbsolutePath(); + } else { + return (String) config.get(); + } + } + + public static void getCategories(Map componentsMap, Map tabs, JComboBox skinComboBox, ResourceBundle resourceBundle) { + Map> categorized = new HashMap<>(); + + Map fields = Configuration.getConfigurationFields(); + String[] keys = new String[fields.size()]; + keys = fields.keySet().toArray(keys); + Arrays.sort(keys); + + for (String name : keys) { + Field field = fields.get(name); + ConfigurationCategory cat = field.getAnnotation(ConfigurationCategory.class); + String scat = (cat == null || cat.value().isEmpty()) ? "other" : cat.value(); + if (!categorized.containsKey(scat)) { + categorized.put(scat, new HashMap<>()); + } + + categorized.get(scat).put(name, field); + } + + for (String cat : categorized.keySet()) { + JPanel configPanel = new JPanel(new SpringLayout()); + int itemCount = 0; + List names = new ArrayList<>(categorized.get(cat).keySet()); + + final Map locNames = new HashMap<>(); + for (String name : names) { + String locName; + + if (resourceBundle.containsKey("config.name." + name)) { + locName = resourceBundle.getString("config.name." + name); + } else { //if it is undocumented, then it must have ConfigurationInternal annotation + Field f = fields.get(name); + ConfigurationInternal cint = f.getAnnotation(ConfigurationInternal.class); + if (cint == null) { + throw new RuntimeException("Missing configuration name: " + name); + } + + locName = "(Internal) " + name; + } + + locNames.put(name, locName); + } + + Collections.sort(names, new Comparator() { + @Override + public int compare(String name1, String name2) { + return locNames.get(name1).compareTo(locNames.get(name2)); + } + }); + for (String name : names) { + Field field = categorized.get(cat).get(name); + + String locName = locNames.get(name); + + try { + ConfigurationItem item = (ConfigurationItem) field.get(null); + + ParameterizedType listType = (ParameterizedType) field.getGenericType(); + java.lang.reflect.Type itemType2 = listType.getActualTypeArguments()[0]; + if (!(itemType2 instanceof Class)) { + continue; + } + + Class itemType = (Class) itemType2; + + String description = ""; + if (resourceBundle.containsKey("config.description." + name)) { + description = resourceBundle.getString("config.description." + name); + } + + Object defaultValue = Configuration.getDefaultValue(field); + if (name.equals("gui.skin")) { + Class c; + try { + c = Class.forName((String) defaultValue); + defaultValue = c.getField("NAME").get(c); + } catch (ClassNotFoundException | NoSuchFieldException | SecurityException ex) { + Logger.getLogger(AdvancedSettingsDialog.class.getName()).log(Level.SEVERE, null, ex); + } + } + + if (defaultValue != null) { + description += " (" + resourceBundle.getString("default") + ": " + defaultValue + ")"; + } + + JLabel l = new JLabel(locName, JLabel.TRAILING); + l.setToolTipText(description); + configPanel.add(l); + Component c = null; + Component addComponent = null; + if (name.equals("gui.skin")) { + skinComboBox.setToolTipText(description); + skinComboBox.setMaximumSize(new Dimension(Integer.MAX_VALUE, skinComboBox.getPreferredSize().height)); + c = skinComboBox; + } else if ((itemType == String.class) || (itemType == Integer.class) || (itemType == Long.class) || (itemType == Double.class) || (itemType == Float.class) || (itemType == Calendar.class)) { + ConfigurationFile confFile = field.getAnnotation(ConfigurationFile.class); + ConfigurationDirectory confDirectory = field.getAnnotation(ConfigurationDirectory.class); + + JTextField tf = new JTextField(); + Object val = item.get(); + if (val == null) { + val = ""; + } + if (itemType == Calendar.class) { + tf.setText(new SimpleDateFormat().format(((Calendar) val).getTime())); + } else { + tf.setText(val.toString()); + } + tf.setToolTipText(description); + tf.setMaximumSize(new Dimension(Integer.MAX_VALUE, tf.getPreferredSize().height)); + + c = tf; + if (confFile != null) { //|| confDirectory != null) { + JPanel p = new JPanel(new BorderLayout()); + p.setMaximumSize(new Dimension(Integer.MAX_VALUE, tf.getPreferredSize().height)); + p.add(tf, BorderLayout.CENTER); + JButton butSelect = new JButton(View.getIcon("folderopen16")); + butSelect.setToolTipText(ResourceBundle.getBundle(AppStrings.getResourcePath(MainFrame.class)).getString("FileChooser.openButtonText")); + butSelect.setMargin(new Insets(2, 2, 2, 2)); + butSelect.addActionListener((ActionEvent e) -> { + tf.setText(selectConfigFile(item, tf.getText(), confFile.value())); + }); + p.add(butSelect, BorderLayout.EAST); + addComponent = p; + } + } else if (itemType == Boolean.class) { + JCheckBox cb = new JCheckBox(); + cb.setSelected((Boolean) item.get()); + cb.setToolTipText(description); + c = cb; + } else if (itemType.isEnum()) { + JComboBox cb = new JComboBox<>(); + @SuppressWarnings("unchecked") + EnumSet enumValues = EnumSet.allOf(itemType); + String stringValue = null; + for (Object enumValue : enumValues) { + String enumValueStr = enumValue.toString(); + if (stringValue == null) { + stringValue = enumValueStr; + } + cb.addItem(enumValueStr); + } + if (item.get() != null) { + stringValue = item.get().toString(); + } + cb.setToolTipText(description); + cb.setSelectedItem(stringValue); + cb.setMaximumSize(new Dimension(Integer.MAX_VALUE, cb.getPreferredSize().height)); + c = cb; + } else { + throw new UnsupportedOperationException("Configuration ttem type '" + itemType.getName() + "' is not supported"); + } + + componentsMap.put(name, c); + if (addComponent == null) { + addComponent = c; + } + l.setLabelFor(c); + configPanel.add(addComponent); + } catch (IllegalArgumentException | IllegalAccessException ex) { + // Reflection exceptions. This should never happen + throw new Error(ex.getMessage()); + } + + itemCount++; + } + + SpringUtilities.makeCompactGrid(configPanel, + itemCount, 2, //rows, cols + 6, 6, //initX, initY + 6, 6); //xPad, yPad + //https://www.adobe.com/support/flashplayer/debug_downloads.html + if (resourceBundle.containsKey("config.group.tip." + cat)) { + String tip = resourceBundle.getString("config.group.tip." + cat); + String url = null; + if (resourceBundle.containsKey("config.group.link." + cat)) { + url = resourceBundle.getString("config.group.link." + cat); + } + JPanel p = new JPanel(new BorderLayout()); + p.add(configPanel, BorderLayout.CENTER); + JPanel tipPanel = new JPanel(new FlowLayout()); + tipPanel.add(new JLabel("" + resourceBundle.getString("tip") + "" + tip + "")); + if (url != null) { + String linkText = url; + if (resourceBundle.containsKey("config.group.linkText." + cat)) { + linkText = resourceBundle.getString("config.group.linkText." + cat); + } + tipPanel.add(new LinkLabel(linkText, url)); + } + p.add(tipPanel, BorderLayout.SOUTH); + configPanel = p; + } + tabs.put(cat, new JScrollPane(configPanel)); + } + } + + private void showRestartConfirmDialod() { + if (View.showConfirmDialog(this, translate("advancedSettings.restartConfirmation"), AppStrings.translate("message.warning"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { + View.execInEventDispatchLater(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + Logger.getLogger(AdvancedSettingsDialog.class.getName()).log(Level.SEVERE, null, ex); + } + SelectLanguageDialog.reloadUi(); + }); + + } + } + + @SuppressWarnings("unchecked") + private void okButtonActionPerformed(ActionEvent evt) { + boolean modified = false; + Map fields = Configuration.getConfigurationFields(); + Map values = new HashMap<>(); + for (String name : fields.keySet()) { + Component c = componentsMap.get(name); + Object value = null; + + ParameterizedType listType = (ParameterizedType) fields.get(name).getGenericType(); + java.lang.reflect.Type itemType2 = listType.getActualTypeArguments()[0]; + if (!(itemType2 instanceof Class)) { + continue; + } + + Class itemType = (Class) itemType2; + if (name.equals("gui.skin")) { + value = ((SkinSelect) ((JComboBox) c).getSelectedItem()).className; + } else if (itemType == String.class) { + value = ((JTextField) c).getText(); + } + if (itemType == Boolean.class) { + value = ((JCheckBox) c).isSelected(); + } + + if (itemType == Calendar.class) { + Calendar cal = Calendar.getInstance(); + try { + cal.setTime(new SimpleDateFormat().parse(((JTextField) c).getText())); + } catch (ParseException ex) { + c.requestFocusInWindow(); + return; + } + value = cal; + } + + if (itemType.isEnum()) { + String stringValue = (String) ((JComboBox) c).getSelectedItem(); + value = Enum.valueOf(itemType, stringValue); + } + + try { + if (itemType == Integer.class) { + value = Integer.parseInt(((JTextField) c).getText()); + } + if (itemType == Long.class) { + value = Long.parseLong(((JTextField) c).getText()); + } + if (itemType == Double.class) { + value = Double.parseDouble(((JTextField) c).getText()); + } + if (itemType == Float.class) { + value = Float.parseFloat(((JTextField) c).getText()); + } + } catch (NumberFormatException nfe) { + if (!((JTextField) c).getText().isEmpty()) { + c.requestFocusInWindow(); + return; + } // else null + } + values.put(name, value); + } + + for (String name : fields.keySet()) { + Component c = componentsMap.get(name); + Object value = values.get(name); + + Field field = fields.get(name); + ConfigurationItem item = null; + try { + item = (ConfigurationItem) field.get(null); + } catch (IllegalArgumentException | IllegalAccessException ex) { + // Reflection exceptions. This should never happen + throw new Error(ex.getMessage()); + } + if (item.get() == null || !item.get().equals(value)) { + if (item.hasValue() || value != null) { + item.set(value); + modified = true; + } + } + } + Configuration.saveConfig(); + setVisible(false); + if (modified) { + showRestartConfirmDialod(); + } + } + + private void cancelButtonActionPerformed(ActionEvent evt) { + setVisible(false); + } + + private void resetButtonActionPerformed(ActionEvent evt) { + Map rfields = Configuration.getConfigurationFields(); + for (Entry entry : rfields.entrySet()) { + String name = entry.getKey(); + Field field = entry.getValue(); + try { + ConfigurationItem item = (ConfigurationItem) field.get(null); + item.unset(); + } catch (IllegalArgumentException | IllegalAccessException ex) { + // Reflection exceptions. This should never happen + throw new Error(ex.getMessage()); + } + } + Configuration.saveConfig(); + setVisible(false); + showRestartConfirmDialod(); + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/QuickFindPanel.java b/src/com/jpexs/decompiler/flash/gui/QuickFindPanel.java index 70742dd6f..ccecbcf8c 100644 --- a/src/com/jpexs/decompiler/flash/gui/QuickFindPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/QuickFindPanel.java @@ -1,247 +1,247 @@ -/* - * Copyright (C) 2010-2016 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 java.awt.Color; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.event.ActionEvent; -import java.lang.ref.WeakReference; -import java.util.ResourceBundle; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; -import javax.swing.BorderFactory; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JTextField; -import javax.swing.SwingUtilities; -import javax.swing.border.BevelBorder; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.text.JTextComponent; -import jsyntaxpane.actions.DocumentSearchData; -import jsyntaxpane.components.Markers; - -/** - * - * @author JPEXS - */ -public class QuickFindPanel extends JPanel { - - public JTextField findTextField; - - public JButton prevButton, nextButton; - - public JCheckBox ignoreCaseCheckbox, regExpCheckbox, wrapCheckbox; - - public JLabel statusLabel; - - private final Markers.SimpleMarker marker = new Markers.SimpleMarker(Color.pink); - - private WeakReference target; - - private WeakReference dsd; - - private int oldCaretPosition; - - public QuickFindPanel() { - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - - setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); - - JPanel pan1 = new JPanel(new WrapLayout()); - JPanel pan2 = new JPanel(new WrapLayout()); - pan1.setAlignmentX(0); - pan2.setAlignmentX(0); - pan1.setAlignmentY(0); - pan2.setAlignmentY(0); - - JLabel jLabel1 = new javax.swing.JLabel(); - findTextField = new javax.swing.JTextField(); - prevButton = new javax.swing.JButton(); - nextButton = new javax.swing.JButton(); - ignoreCaseCheckbox = new javax.swing.JCheckBox(); - regExpCheckbox = new javax.swing.JCheckBox(); - wrapCheckbox = new javax.swing.JCheckBox(); - statusLabel = new javax.swing.JLabel(); - - setName("QuickFindDialog"); - - jLabel1.setLabelFor(findTextField); - ResourceBundle bundle = ResourceBundle.getBundle("jsyntaxpane/Bundle"); - jLabel1.setText(bundle.getString("QuickFindDialog.jLabel1.text")); - pan1.add(jLabel1); - - findTextField.setColumns(30); - findTextField.setBorder(javax.swing.BorderFactory.createLineBorder(Color.black)); - findTextField.setMaximumSize(new java.awt.Dimension(200, 24)); - findTextField.setMinimumSize(new java.awt.Dimension(60, 24)); - pan1.add(findTextField); - - prevButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/META-INF/images/small-icons/go-up.png"))); - prevButton.setFocusable(false); - prevButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - prevButton.setOpaque(false); - prevButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - prevButton.addActionListener(this::previousButtonActionPerformed); - pan1.add(prevButton); - - nextButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/META-INF/images/small-icons/go-down.png"))); - nextButton.setFocusable(false); - nextButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - nextButton.setMargin(new java.awt.Insets(2, 2, 2, 2)); - nextButton.setOpaque(false); - nextButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - nextButton.addActionListener(this::nextButtonActionPerformed); - pan1.add(nextButton); - - ignoreCaseCheckbox.setMnemonic('C'); - ignoreCaseCheckbox.setText(bundle.getString("QuickFindDialog.jChkIgnoreCase.text")); - ignoreCaseCheckbox.setFocusable(false); - ignoreCaseCheckbox.setOpaque(false); - ignoreCaseCheckbox.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - pan2.add(ignoreCaseCheckbox); - //ignoreCaseCheckbox.addActionListener(this); - - regExpCheckbox.setMnemonic('R'); - regExpCheckbox.setText(bundle.getString("QuickFindDialog.jChkRegExp.text")); - regExpCheckbox.setFocusable(false); - regExpCheckbox.setOpaque(false); - regExpCheckbox.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - pan2.add(regExpCheckbox); - //regExpCheckbox.addActionListener(this); - - wrapCheckbox.setMnemonic('W'); - wrapCheckbox.setText(bundle.getString("QuickFindDialog.jChkWrap.text")); - wrapCheckbox.setFocusable(false); - wrapCheckbox.setOpaque(false); - wrapCheckbox.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - pan2.add(wrapCheckbox); - //wrapCheckbox.addActionListener(this); - - statusLabel.setFont(statusLabel.getFont().deriveFont(statusLabel.getFont().getStyle() | java.awt.Font.BOLD, statusLabel.getFont().getSize() - 2)); - statusLabel.setForeground(Color.red); - pan2.add(statusLabel); - - add(pan1); - add(pan2); - setPreferredSize(getMinimumSize()); - setVisible(false); - } - - private void previousButtonActionPerformed(ActionEvent evt) { - if (dsd.get().doFindPrev(target.get())) { - statusLabel.setText(null); - } else { - statusLabel.setText(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.NotFound")); - } - } - - private void nextButtonActionPerformed(ActionEvent evt) { - if (dsd.get().doFindNext(target.get())) { - statusLabel.setText(null); - } else { - statusLabel.setText(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.NotFound")); - } - } - - public void showQuickFind(final JTextComponent t, DocumentSearchData ds) { - dsd = new WeakReference<>(ds); - oldCaretPosition = t.getCaretPosition(); - Container view = t.getParent(); - Dimension wd = getSize(); - wd.width = t.getVisibleRect().width; - Point loc = new Point(0, view.getHeight()); - setSize(wd); - SwingUtilities.convertPointToScreen(loc, view); - setLocation(loc); - findTextField.setFont(t.getFont()); - final DocumentListener dl; - findTextField.getDocument().addDocumentListener(dl = new DocumentListener() { - - @Override - public void insertUpdate(DocumentEvent e) { - updateFind(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - updateFind(); - } - - @Override - public void changedUpdate(DocumentEvent e) { - updateFind(); - } - - private void updateFind() { - JTextComponent t = target.get(); - DocumentSearchData d = dsd.get(); - String toFind = findTextField.getText(); - if (toFind == null || toFind.isEmpty()) { - statusLabel.setText(null); - return; - } - try { - d.setWrap(wrapCheckbox.isSelected()); - d.setPattern(toFind, - regExpCheckbox.isSelected(), - ignoreCaseCheckbox.isSelected()); - // The dsd doFindNext will always find from current pos, - // so we need to relocate to our saved pos before we call doFindNext - statusLabel.setText(null); - t.setCaretPosition(oldCaretPosition); - if (!d.doFindNext(t)) { - statusLabel.setText(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.NotFound")); - } else { - statusLabel.setText(null); - } - } catch (PatternSyntaxException e) { - statusLabel.setText(e.getDescription()); - } - } - }); - this.target = new WeakReference<>(t); - Pattern p = dsd.get().getPattern(); - if (p != null) { - findTextField.setText(p.pattern()); - } - wrapCheckbox.setSelected(dsd.get().isWrap()); - - setVisible(true); - getParent().revalidate(); - getParent().repaint(); - findTextField.requestFocusInWindow(); - } - /* - @Override - public void focusGained(FocusEvent e) { - - } - - @Override - public void focusLost(FocusEvent e) { - removeFocusListener(this); - setVisible(false); - getParent().revalidate(); - getParent().repaint(); - }*/ -} +/* + * Copyright (C) 2010-2016 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 java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.lang.ref.WeakReference; +import java.util.ResourceBundle; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.border.BevelBorder; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.JTextComponent; +import jsyntaxpane.actions.DocumentSearchData; +import jsyntaxpane.components.Markers; + +/** + * + * @author JPEXS + */ +public class QuickFindPanel extends JPanel { + + public JTextField findTextField; + + public JButton prevButton, nextButton; + + public JCheckBox ignoreCaseCheckbox, regExpCheckbox, wrapCheckbox; + + public JLabel statusLabel; + + private final Markers.SimpleMarker marker = new Markers.SimpleMarker(Color.pink); + + private WeakReference target; + + private WeakReference dsd; + + private int oldCaretPosition; + + public QuickFindPanel() { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); + + JPanel pan1 = new JPanel(new WrapLayout()); + JPanel pan2 = new JPanel(new WrapLayout()); + pan1.setAlignmentX(0); + pan2.setAlignmentX(0); + pan1.setAlignmentY(0); + pan2.setAlignmentY(0); + + JLabel jLabel1 = new javax.swing.JLabel(); + findTextField = new javax.swing.JTextField(); + prevButton = new javax.swing.JButton(); + nextButton = new javax.swing.JButton(); + ignoreCaseCheckbox = new javax.swing.JCheckBox(); + regExpCheckbox = new javax.swing.JCheckBox(); + wrapCheckbox = new javax.swing.JCheckBox(); + statusLabel = new javax.swing.JLabel(); + + setName("QuickFindDialog"); + + jLabel1.setLabelFor(findTextField); + ResourceBundle bundle = ResourceBundle.getBundle("jsyntaxpane/Bundle"); + jLabel1.setText(bundle.getString("QuickFindDialog.jLabel1.text")); + pan1.add(jLabel1); + + findTextField.setColumns(30); + findTextField.setBorder(javax.swing.BorderFactory.createLineBorder(Color.black)); + findTextField.setMaximumSize(new java.awt.Dimension(200, 24)); + findTextField.setMinimumSize(new java.awt.Dimension(60, 24)); + pan1.add(findTextField); + + prevButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/META-INF/images/small-icons/go-up.png"))); + prevButton.setFocusable(false); + prevButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + prevButton.setOpaque(false); + prevButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + prevButton.addActionListener(this::previousButtonActionPerformed); + pan1.add(prevButton); + + nextButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/META-INF/images/small-icons/go-down.png"))); + nextButton.setFocusable(false); + nextButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + nextButton.setMargin(new java.awt.Insets(2, 2, 2, 2)); + nextButton.setOpaque(false); + nextButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + nextButton.addActionListener(this::nextButtonActionPerformed); + pan1.add(nextButton); + + ignoreCaseCheckbox.setMnemonic('C'); + ignoreCaseCheckbox.setText(bundle.getString("QuickFindDialog.jChkIgnoreCase.text")); + ignoreCaseCheckbox.setFocusable(false); + ignoreCaseCheckbox.setOpaque(false); + ignoreCaseCheckbox.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + pan2.add(ignoreCaseCheckbox); + //ignoreCaseCheckbox.addActionListener(this); + + regExpCheckbox.setMnemonic('R'); + regExpCheckbox.setText(bundle.getString("QuickFindDialog.jChkRegExp.text")); + regExpCheckbox.setFocusable(false); + regExpCheckbox.setOpaque(false); + regExpCheckbox.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + pan2.add(regExpCheckbox); + //regExpCheckbox.addActionListener(this); + + wrapCheckbox.setMnemonic('W'); + wrapCheckbox.setText(bundle.getString("QuickFindDialog.jChkWrap.text")); + wrapCheckbox.setFocusable(false); + wrapCheckbox.setOpaque(false); + wrapCheckbox.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + pan2.add(wrapCheckbox); + //wrapCheckbox.addActionListener(this); + + statusLabel.setFont(statusLabel.getFont().deriveFont(statusLabel.getFont().getStyle() | java.awt.Font.BOLD, statusLabel.getFont().getSize() - 2)); + statusLabel.setForeground(Color.red); + pan2.add(statusLabel); + + add(pan1); + add(pan2); + setPreferredSize(getMinimumSize()); + setVisible(false); + } + + private void previousButtonActionPerformed(ActionEvent evt) { + if (dsd.get().doFindPrev(target.get())) { + statusLabel.setText(null); + } else { + statusLabel.setText(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.NotFound")); + } + } + + private void nextButtonActionPerformed(ActionEvent evt) { + if (dsd.get().doFindNext(target.get())) { + statusLabel.setText(null); + } else { + statusLabel.setText(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.NotFound")); + } + } + + public void showQuickFind(final JTextComponent t, DocumentSearchData ds) { + dsd = new WeakReference<>(ds); + oldCaretPosition = t.getCaretPosition(); + Container view = t.getParent(); + Dimension wd = getSize(); + wd.width = t.getVisibleRect().width; + Point loc = new Point(0, view.getHeight()); + setSize(wd); + SwingUtilities.convertPointToScreen(loc, view); + setLocation(loc); + findTextField.setFont(t.getFont()); + final DocumentListener dl; + findTextField.getDocument().addDocumentListener(dl = new DocumentListener() { + + @Override + public void insertUpdate(DocumentEvent e) { + updateFind(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + updateFind(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + updateFind(); + } + + private void updateFind() { + JTextComponent t = target.get(); + DocumentSearchData d = dsd.get(); + String toFind = findTextField.getText(); + if (toFind == null || toFind.isEmpty()) { + statusLabel.setText(null); + return; + } + try { + d.setWrap(wrapCheckbox.isSelected()); + d.setPattern(toFind, + regExpCheckbox.isSelected(), + ignoreCaseCheckbox.isSelected()); + // The dsd doFindNext will always find from current pos, + // so we need to relocate to our saved pos before we call doFindNext + statusLabel.setText(null); + t.setCaretPosition(oldCaretPosition); + if (!d.doFindNext(t)) { + statusLabel.setText(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.NotFound")); + } else { + statusLabel.setText(null); + } + } catch (PatternSyntaxException e) { + statusLabel.setText(e.getDescription()); + } + } + }); + this.target = new WeakReference<>(t); + Pattern p = dsd.get().getPattern(); + if (p != null) { + findTextField.setText(p.pattern()); + } + wrapCheckbox.setSelected(dsd.get().isWrap()); + + setVisible(true); + getParent().revalidate(); + getParent().repaint(); + findTextField.requestFocusInWindow(); + } + /* + @Override + public void focusGained(FocusEvent e) { + + } + + @Override + public void focusLost(FocusEvent e) { + removeFocusListener(this); + setVisible(false); + getParent().revalidate(); + getParent().repaint(); + }*/ +} diff --git a/src/com/jpexs/decompiler/flash/gui/SearchPanel.java b/src/com/jpexs/decompiler/flash/gui/SearchPanel.java index 7d3effb8b..1212b83f5 100644 --- a/src/com/jpexs/decompiler/flash/gui/SearchPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/SearchPanel.java @@ -1,142 +1,142 @@ -/* - * Copyright (C) 2010-2016 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 java.awt.Insets; -import java.awt.LayoutManager; -import java.awt.event.ActionEvent; -import java.util.ArrayList; -import java.util.List; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.text.JTextComponent; -import jsyntaxpane.actions.DocumentSearchData; - -/** - * - * @author JPEXS - * @param Element to search - */ -public class SearchPanel extends JPanel { - - private final SearchListener listener; - - private final JLabel searchPos; - - private int foundPos = 0; - - private final JLabel searchForLabel; - - private String searchFor; - - private boolean searchIgnoreCase; - - private boolean searchRegexp; - - private List found = new ArrayList<>(); - - public SearchPanel(LayoutManager lm, SearchListener listener) { - super(lm); - - this.listener = listener; - - JButton prevSearchButton = new JButton(View.getIcon("prev16")); - prevSearchButton.setMargin(new Insets(3, 3, 3, 3)); - prevSearchButton.addActionListener(this::prevButtonActionPerformed); - JButton nextSearchButton = new JButton(View.getIcon("next16")); - nextSearchButton.setMargin(new Insets(3, 3, 3, 3)); - nextSearchButton.addActionListener(this::nextButtonActionPerformed); - JButton cancelSearchButton = new JButton(View.getIcon("cancel16")); - cancelSearchButton.setMargin(new Insets(3, 3, 3, 3)); - cancelSearchButton.addActionListener(this::cancelButtonActionPerformed); - searchPos = new JLabel("0/0"); - searchForLabel = new JLabel(AppStrings.translate("search.info").replace("%text%", "")); - add(searchForLabel); - add(prevSearchButton); - add(new JLabel(AppStrings.translate("search.script") + " ")); - add(searchPos); - add(nextSearchButton); - add(cancelSearchButton); - setVisible(false); - } - - public void showQuickFindDialog(JTextComponent editor) { - DocumentSearchData dsd = DocumentSearchData.getFromEditor(editor); - dsd.setPattern(searchFor, searchRegexp, searchIgnoreCase); - dsd.showQuickFindDialogEx(editor, searchIgnoreCase, searchRegexp); - } - - public void setSearchText(String txt) { - searchFor = txt; - searchForLabel.setText(AppStrings.translate("search.info").replace("%text%", txt) + " "); - } - - public boolean setResults(List results) { - found = results; - if (found.isEmpty()) { - setVisible(false); - return false; - } else { - setPos(0); - setVisible(true); - return true; - } - } - - public void setOptions(boolean ignoreCase, boolean regExp) { - searchIgnoreCase = ignoreCase; - searchRegexp = regExp; - } - - public void setPos(int pos) { - foundPos = pos; - doUpdate(); - } - - public void clear() { - foundPos = 0; - found.clear(); - } - - private void doUpdate() { - View.execInEventDispatchLater(() -> { - searchPos.setText((foundPos + 1) + "/" + found.size()); - listener.updateSearchPos(found.get(foundPos)); - }); - } - - private void cancelButtonActionPerformed(ActionEvent evt) { - foundPos = 0; - setVisible(false); - found = new ArrayList<>(); - searchFor = null; - } - - private void prevButtonActionPerformed(ActionEvent evt) { - foundPos--; - if (foundPos < 0) { - foundPos += found.size(); - } - doUpdate(); - } - - private void nextButtonActionPerformed(ActionEvent evt) { - foundPos = (foundPos + 1) % found.size(); - doUpdate(); - } -} +/* + * Copyright (C) 2010-2016 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 java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.List; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.text.JTextComponent; +import jsyntaxpane.actions.DocumentSearchData; + +/** + * + * @author JPEXS + * @param Element to search + */ +public class SearchPanel extends JPanel { + + private final SearchListener listener; + + private final JLabel searchPos; + + private int foundPos = 0; + + private final JLabel searchForLabel; + + private String searchFor; + + private boolean searchIgnoreCase; + + private boolean searchRegexp; + + private List found = new ArrayList<>(); + + public SearchPanel(LayoutManager lm, SearchListener listener) { + super(lm); + + this.listener = listener; + + JButton prevSearchButton = new JButton(View.getIcon("prev16")); + prevSearchButton.setMargin(new Insets(3, 3, 3, 3)); + prevSearchButton.addActionListener(this::prevButtonActionPerformed); + JButton nextSearchButton = new JButton(View.getIcon("next16")); + nextSearchButton.setMargin(new Insets(3, 3, 3, 3)); + nextSearchButton.addActionListener(this::nextButtonActionPerformed); + JButton cancelSearchButton = new JButton(View.getIcon("cancel16")); + cancelSearchButton.setMargin(new Insets(3, 3, 3, 3)); + cancelSearchButton.addActionListener(this::cancelButtonActionPerformed); + searchPos = new JLabel("0/0"); + searchForLabel = new JLabel(AppStrings.translate("search.info").replace("%text%", "")); + add(searchForLabel); + add(prevSearchButton); + add(new JLabel(AppStrings.translate("search.script") + " ")); + add(searchPos); + add(nextSearchButton); + add(cancelSearchButton); + setVisible(false); + } + + public void showQuickFindDialog(JTextComponent editor) { + DocumentSearchData dsd = DocumentSearchData.getFromEditor(editor); + dsd.setPattern(searchFor, searchRegexp, searchIgnoreCase); + dsd.showQuickFindDialogEx(editor, searchIgnoreCase, searchRegexp); + } + + public void setSearchText(String txt) { + searchFor = txt; + searchForLabel.setText(AppStrings.translate("search.info").replace("%text%", txt) + " "); + } + + public boolean setResults(List results) { + found = results; + if (found.isEmpty()) { + setVisible(false); + return false; + } else { + setPos(0); + setVisible(true); + return true; + } + } + + public void setOptions(boolean ignoreCase, boolean regExp) { + searchIgnoreCase = ignoreCase; + searchRegexp = regExp; + } + + public void setPos(int pos) { + foundPos = pos; + doUpdate(); + } + + public void clear() { + foundPos = 0; + found.clear(); + } + + private void doUpdate() { + View.execInEventDispatchLater(() -> { + searchPos.setText((foundPos + 1) + "/" + found.size()); + listener.updateSearchPos(found.get(foundPos)); + }); + } + + private void cancelButtonActionPerformed(ActionEvent evt) { + foundPos = 0; + setVisible(false); + found = new ArrayList<>(); + searchFor = null; + } + + private void prevButtonActionPerformed(ActionEvent evt) { + foundPos--; + if (foundPos < 0) { + foundPos += found.size(); + } + doUpdate(); + } + + private void nextButtonActionPerformed(ActionEvent evt) { + foundPos = (foundPos + 1) % found.size(); + doUpdate(); + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java index 91184b9b8..44430615e 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java @@ -1,728 +1,728 @@ -/* - * Copyright (C) 2010-2016 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.abc; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.CachedDecompilation; -import com.jpexs.decompiler.flash.abc.ScriptPack; -import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; -import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; -import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructSuperIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallSuperIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallSuperVoidIns; -import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; -import com.jpexs.decompiler.flash.abc.types.ClassInfo; -import com.jpexs.decompiler.flash.abc.types.InstanceInfo; -import com.jpexs.decompiler.flash.abc.types.Multiname; -import com.jpexs.decompiler.flash.abc.types.ScriptInfo; -import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction; -import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; -import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; -import com.jpexs.decompiler.flash.gui.AppStrings; -import com.jpexs.decompiler.flash.gui.View; -import com.jpexs.decompiler.flash.gui.editor.DebuggableEditorPane; -import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.flash.helpers.hilight.HighlightData; -import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; -import com.jpexs.decompiler.flash.helpers.hilight.Highlighting; -import com.jpexs.decompiler.flash.tags.ABCContainerTag; -import com.jpexs.decompiler.graph.DottedChain; -import java.awt.Point; -import java.util.ArrayList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; -import jsyntaxpane.SyntaxDocument; -import jsyntaxpane.Token; -import jsyntaxpane.TokenType; - -/** - * - * @author JPEXS - */ -public class DecompiledEditorPane extends DebuggableEditorPane implements CaretListener { - - private List highlights = new ArrayList<>(); - - private List specialHighlights = new ArrayList<>(); - - private List traitHighlights = new ArrayList<>(); - - private List methodHighlights = new ArrayList<>(); - - private List classHighlights = new ArrayList<>(); - - private Highlighting currentMethodHighlight; - - private Highlighting currentTraitHighlight; - - private ScriptPack script; - - public int lastTraitIndex = 0; - - public boolean ignoreCarret = false; - - private boolean reset = false; - - private final ABCPanel abcPanel; - - private int classIndex = -1; - - private boolean isStatic = false; - - private final List scriptListeners = new ArrayList<>(); - - public void addScriptListener(Runnable l) { - scriptListeners.add(l); - } - - public ABCPanel getAbcPanel() { - return abcPanel; - } - - public void removeScriptListener(Runnable l) { - scriptListeners.remove(l); - } - - public void fireScript() { - Runnable[] listeners = scriptListeners.toArray(new Runnable[scriptListeners.size()]); - for (Runnable scriptListener : listeners) { - scriptListener.run(); - } - } - - public Trait getCurrentTrait() { - return script.abc.findTraitByTraitId(classIndex, lastTraitIndex); - } - - public ScriptPack getScriptLeaf() { - return script; - } - - public boolean getIsStatic() { - return isStatic; - } - - public void setNoTrait() { - abcPanel.detailPanel.showCard(DetailPanel.UNSUPPORTED_TRAIT_CARD, null); - } - - public void hilightSpecial(HighlightSpecialType type, long index) { - int startPos; - int endPos; - if (currentMethodHighlight == null) { - if (currentTraitHighlight == null) { - return; - } - startPos = currentTraitHighlight.startPos; - endPos = currentTraitHighlight.startPos + currentTraitHighlight.len; - } else { - startPos = currentMethodHighlight.startPos; - endPos = currentMethodHighlight.startPos + currentMethodHighlight.len; - } - - List allh = new ArrayList<>(); - for (Highlighting h : traitHighlights) { - if (h.getProperties().index == lastTraitIndex) { - for (Highlighting sh : specialHighlights) { - if (sh.startPos >= h.startPos && (sh.startPos + sh.len < h.startPos + h.len)) { - allh.add(sh); - } - } - } - } - if (currentMethodHighlight != null) { - for (Highlighting h : specialHighlights) { - if (h.startPos >= startPos && (h.startPos + h.len < endPos)) { - allh.add(h); - } - } - } - for (Highlighting h : allh) { - if (h.getProperties().subtype.equals(type) && (h.getProperties().index == index)) { - ignoreCarret = true; - if (h.startPos <= getDocument().getLength()) { - setCaretPosition(h.startPos); - } - getCaret().setVisible(true); - ignoreCarret = false; - break; - } - } - } - - public void hilightOffset(long offset) { - if (currentMethodHighlight == null) { - return; - } - for (Highlighting h : traitHighlights) { - if (h.getProperties().index == lastTraitIndex) { - Highlighting h2 = Highlighting.searchOffset(highlights, offset, h.startPos, h.startPos + h.len); - if (h2 != null) { - ignoreCarret = true; - if (h2.startPos <= getDocument().getLength()) { - setCaretPosition(h2.startPos); - } - getCaret().setVisible(true); - ignoreCarret = false; - } - - } - } - } - - public void setClassIndex(int classIndex) { - this.classIndex = classIndex; - } - - private boolean displayMethod(int pos, int methodIndex, String name, Trait trait, boolean isStatic) { - ABC abc = getABC(); - if (abc == null) { - return false; - } - int bi = abc.findBodyIndex(methodIndex); - if (bi == -1) { - return false; - } - - //fix for inner functions: - if (trait instanceof TraitMethodGetterSetter) { - TraitMethodGetterSetter tm = (TraitMethodGetterSetter) trait; - if (tm.method_info != methodIndex) { - trait = null; - } - } - if (trait instanceof TraitFunction) { - TraitFunction tf = (TraitFunction) trait; - if (tf.method_info != methodIndex) { - trait = null; - } - } - abcPanel.detailPanel.showCard(DetailPanel.METHOD_TRAIT_CARD, trait); - MethodCodePanel methodCodePanel = abcPanel.detailPanel.methodTraitPanel.methodCodePanel; - if (reset || (methodCodePanel.getBodyIndex() != bi)) { - methodCodePanel.setBodyIndex(scriptName, bi, abc, name, trait, script.scriptIndex); - abcPanel.detailPanel.setEditMode(false); - this.isStatic = isStatic; - } - boolean success = false; - Highlighting h = Highlighting.searchPos(highlights, pos); - if (h != null) { - methodCodePanel.hilighOffset(h.getProperties().offset); - success = true; - } - Highlighting sh = Highlighting.searchPos(specialHighlights, pos); - if (sh != null) { - methodCodePanel.hilighSpecial(sh.getProperties().subtype, sh.getProperties().specialValue); - success = true; - } - return success; - } - - public void displayClass(int classIndex, int scriptIndex) { - if (abcPanel.navigator.getClassIndex() != classIndex) { - abcPanel.navigator.setClassIndex(classIndex, scriptIndex); - } - } - - public void resetEditing() { - reset = true; - caretUpdate(null); - reset = false; - } - - public int getMultinameUnderMouseCursor(Point pt) { - return getMultinameAtPos(viewToModel(pt)); - } - - public int getMultinameUnderCaret() { - return getMultinameAtPos(getCaretPosition()); - } - - public int getLocalDeclarationOfPos(int pos, Reference type) { - Highlighting sh = Highlighting.searchPos(specialHighlights, pos); - Highlighting h = Highlighting.searchPos(highlights, pos); - - if (h == null) { - return -1; - } - - List tms = Highlighting.searchAllPos(methodHighlights, pos); - if (tms.isEmpty()) { - return -1; - } - for (Highlighting tm : tms) { - - List tm_tms = Highlighting.searchAllIndexes(methodHighlights, tm.getProperties().index); - //is it already declaration? - if (h.getProperties().declaration || (sh != null && sh.getProperties().declaration)) { - return -1; //no jump - } - - String lname = h.getProperties().localName; - if ("this".equals(lname)) { - Highlighting ch = Highlighting.searchPos(classHighlights, pos); - int cindex = (int) ch.getProperties().index; - ABC abc = getABC(); - type.setVal(abc.instance_info.get(cindex).getName(abc.constants).getNameWithNamespace(abc.constants)); - return ch.startPos; - } - - HighlightData hData = h.getProperties(); - HighlightData search = new HighlightData(); - search.declaration = hData.declaration; - search.declaredType = hData.declaredType; - search.localName = hData.localName; - search.specialValue = hData.specialValue; - if (search.isEmpty()) { - return -1; - } - search.declaration = true; - - for (Highlighting tm1 : tm_tms) { - Highlighting rh = Highlighting.search(highlights, search, tm1.startPos, tm1.startPos + tm1.len); - if (rh == null) { - rh = Highlighting.search(specialHighlights, search, tm1.startPos, tm1.startPos + tm1.len); - } - if (rh != null) { - type.setVal(rh.getProperties().declaredType); - return rh.startPos; - } - } - } - - return -1; - } - - public boolean getPropertyTypeAtPos(int pos, Reference abcIndex, Reference classIndex, Reference traitIndex, Reference classTrait, Reference multinameIndex) { - - int m = getMultinameAtPos(pos, true); - if (m <= 0) { - return false; - } - SyntaxDocument sd = (SyntaxDocument) getDocument(); - Token t = sd.getTokenAt(pos + 1); - Token lastToken = t; - Token prev; - while (t.type == TokenType.IDENTIFIER || t.type == TokenType.KEYWORD || t.type == TokenType.REGEX) { - prev = sd.getPrevToken(t); - if (prev != null) { - if (!".".equals(prev.getString(sd))) { - break; - } - t = sd.getPrevToken(prev); - } else { - break; - } - } - if (t.type != TokenType.IDENTIFIER && t.type != TokenType.KEYWORD || t.type == TokenType.REGEX) { - return false; - } - Reference locTypeRef = new Reference<>(DottedChain.EMPTY); - getLocalDeclarationOfPos(t.start, locTypeRef); - DottedChain currentType = locTypeRef.getVal(); - if (currentType.equals(DottedChain.ALL)) { - return false; - } - boolean found; - t = sd.getNextToken(t); - while (t != lastToken && !currentType.equals(DottedChain.ALL)) { - t = sd.getNextToken(t); - String ident = t.getString(sd); - found = false; - List abcList = getABC().getSwf().getAbcList(); - loopi: - for (int i = 0; i < abcList.size(); i++) { - ABC a = abcList.get(i).getABC(); - int cindex = a.findClassByName(currentType); - if (cindex > -1) { - InstanceInfo ii = a.instance_info.get(cindex); - for (int j = 0; j < ii.instance_traits.traits.size(); j++) { - Trait tr = ii.instance_traits.traits.get(j); - if (ident.equals(tr.getName(a).getName(a.constants, null, false /*NOT RAW!*/))) { - classIndex.setVal(cindex); - abcIndex.setVal(i); - traitIndex.setVal(j); - classTrait.setVal(false); - multinameIndex.setVal(tr.name_index); - currentType = ii.getName(a.constants).getNameWithNamespace(a.constants); - found = true; - break loopi; - } - } - - ClassInfo ci = a.class_info.get(cindex); - for (int j = 0; j < ci.static_traits.traits.size(); j++) { - Trait tr = ci.static_traits.traits.get(j); - if (ident.equals(tr.getName(a).getName(a.constants, null, false /*NOT RAW!*/))) { - classIndex.setVal(cindex); - abcIndex.setVal(i); - traitIndex.setVal(j); - classTrait.setVal(true); - multinameIndex.setVal(tr.name_index); - currentType = ii.getName(a.constants).getNameWithNamespace(a.constants); - found = true; - break loopi; - } - } - } - } - if (!found) { - return false; - } - - t = sd.getNextToken(t); - if (!".".equals(t.getString(sd))) { - break; - } - } - return true; - } - - public int getMultinameAtPos(int pos) { - return getMultinameAtPos(pos, false); - } - - private int getMultinameAtPos(int pos, boolean codeOnly) { - int multinameIndex = _getMultinameAtPos(pos, codeOnly); - if (multinameIndex > -1) { - ABC abc = getABC(); - multinameIndex = abc.constants.convertToQname(abc.constants, multinameIndex); - } - return multinameIndex; - } - - public int _getMultinameAtPos(int pos, boolean codeOnly) { - Highlighting tm = Highlighting.searchPos(methodHighlights, pos); - Trait currentTrait = null; - int currentMethod = -1; - ABC abc = getABC(); - if (tm != null) { - - int mi = (int) tm.getProperties().index; - currentMethod = mi; - int bi = abc.findBodyIndex(mi); - Highlighting h = Highlighting.searchPos(highlights, pos); - if (h != null) { - long highlightOffset = h.getProperties().offset; - List list = abc.bodies.get(bi).getCode().code; - AVM2Instruction lastIns = null; - AVM2Instruction selIns = null; - for (AVM2Instruction ins : list) { - if (highlightOffset == ins.getAddress()) { - selIns = ins; - break; - } - if (ins.getAddress() > highlightOffset) { - selIns = lastIns; - break; - } - lastIns = ins; - } - if (selIns != null) { - //long inspos = highlightOffset - selIns.offset; - if (!codeOnly && ((selIns.definition instanceof ConstructSuperIns) || (selIns.definition instanceof CallSuperIns) || (selIns.definition instanceof CallSuperVoidIns))) { - Highlighting tc = Highlighting.searchPos(classHighlights, pos); - if (tc != null) { - int cindex = (int) tc.getProperties().index; - if (cindex > -1) { - return abc.instance_info.get(cindex).super_index; - } - } - } else { - for (int i = 0; i < selIns.definition.operands.length; i++) { - if (selIns.definition.operands[i] == AVM2Code.DAT_MULTINAME_INDEX) { - return selIns.operands[i]; - } - } - } - } - } - - } - if (codeOnly) { - return -1; - } - - Highlighting ch = Highlighting.searchPos(classHighlights, pos); - if (ch != null) { - Highlighting th = Highlighting.searchPos(traitHighlights, pos); - if (th != null) { - currentTrait = abc.findTraitByTraitId((int) ch.getProperties().index, (int) th.getProperties().index); - } - } - - if (currentTrait instanceof TraitMethodGetterSetter) { - currentMethod = ((TraitMethodGetterSetter) currentTrait).method_info; - } - Highlighting sh = Highlighting.searchPos(specialHighlights, pos); - if (sh != null) { - switch (sh.getProperties().subtype) { - case TYPE_NAME: - String typeName = sh.getProperties().specialValue; - for (int i = 1; i < abc.constants.getMultinameCount(); i++) { - Multiname m = abc.constants.getMultiname(i); - if (m != null) { - if (typeName.equals(m.getNameWithNamespace(abc.constants).toRawString())) { - return i; - } - } - } - case TRAIT_TYPE_NAME: - if (currentTrait instanceof TraitSlotConst) { - TraitSlotConst ts = (TraitSlotConst) currentTrait; - return ts.type_index; - } - break; - case TRAIT_NAME: - if (currentTrait != null) { - //return currentTrait.name_index; - } - break; - case RETURNS: - if (currentMethod > -1) { - return abc.method_info.get(currentMethod).ret_type; - } - break; - case PARAM: - if (currentMethod > -1) { - return abc.method_info.get(currentMethod).param_types[(int) sh.getProperties().index]; - } - break; - } - } - return -1; - } - - @Override - public void caretUpdate(final CaretEvent e) { - ABC abc = getABC(); - if (abc == null) { - return; - } - if (ignoreCarret) { - return; - } - - getCaret().setVisible(true); - int pos = getCaretPosition(); - abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setIgnoreCarret(true); - try { - classIndex = -1; - Highlighting cm = Highlighting.searchPos(classHighlights, pos); - if (cm != null) { - classIndex = (int) cm.getProperties().index; - } - displayClass(classIndex, script.scriptIndex); - Highlighting tm = Highlighting.searchPos(methodHighlights, pos); - if (tm != null) { - String name = ""; - if (classIndex > -1) { - name = abc.instance_info.get(classIndex).getName(abc.constants).getNameWithNamespace(abc.constants).toPrintableString(true); - } - - Trait currentTrait = null; - currentTraitHighlight = Highlighting.searchPos(traitHighlights, pos); - if (currentTraitHighlight != null) { - lastTraitIndex = (int) currentTraitHighlight.getProperties().index; - if (classIndex != -1) { - currentTrait = getCurrentTrait(); - isStatic = abc.isStaticTraitId(classIndex, lastTraitIndex); - if (currentTrait != null) { - name += ":" + currentTrait.getName(abc).getName(abc.constants, null, false); - } - } - } - - displayMethod(pos, (int) tm.getProperties().index, name, currentTrait, isStatic); - currentMethodHighlight = tm; - return; - } - - if (classIndex == -1) { - abcPanel.navigator.setClassIndex(-1, script.scriptIndex); - setNoTrait(); - return; - } - Trait currentTrait; - currentTraitHighlight = Highlighting.searchPos(traitHighlights, pos); - if (currentTraitHighlight != null) { - lastTraitIndex = (int) currentTraitHighlight.getProperties().index; - currentTrait = getCurrentTrait(); - if (currentTrait != null) { - if (currentTrait instanceof TraitSlotConst) { - abcPanel.detailPanel.slotConstTraitPanel.load((TraitSlotConst) currentTrait, abc, - abc.isStaticTraitId(classIndex, lastTraitIndex)); - final Trait ftrait = currentTrait; - View.execInEventDispatch(() -> { - abcPanel.detailPanel.showCard(DetailPanel.SLOT_CONST_TRAIT_CARD, ftrait); - }); - abcPanel.detailPanel.setEditMode(false); - currentMethodHighlight = null; - Highlighting spec = Highlighting.searchPos(specialHighlights, pos, currentTraitHighlight.startPos, currentTraitHighlight.startPos + currentTraitHighlight.len); - if (spec != null) { - abcPanel.detailPanel.slotConstTraitPanel.hilightSpecial(spec); - } - - return; - } - } - currentMethodHighlight = null; - //currentTrait = null; - String name = abc.instance_info.get(classIndex).getName(abc.constants).getNameWithNamespace(abc.constants).toPrintableString(true); - currentTrait = getCurrentTrait(); - isStatic = abc.isStaticTraitId(classIndex, lastTraitIndex); - if (currentTrait != null) { - name += ":" + currentTrait.getName(abc).getName(abc.constants, null, false); - } - - displayMethod(pos, abc.findMethodIdByTraitId(classIndex, lastTraitIndex), name, currentTrait, isStatic); - return; - } - setNoTrait(); - } finally { - abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setIgnoreCarret(false); - } - } - - public void gotoLastTrait() { - gotoTrait(lastTraitIndex); - } - - public void gotoTrait(int traitId) { - boolean isScriptInit = traitId == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER; - - Highlighting tc = Highlighting.searchIndex(classHighlights, classIndex); - if (tc != null || isScriptInit) { - Highlighting th = Highlighting.searchIndex(traitHighlights, traitId, isScriptInit || tc == null ? 0 : tc.startPos, isScriptInit || tc == null ? -1 : tc.startPos + tc.len); - int pos = 0; - if (th != null) { - if (th.len > 1) { - ignoreCarret = true; - int startPos = th.startPos + th.len - 1; - if (startPos <= getDocument().getLength()) { - setCaretPosition(startPos); - } - ignoreCarret = false; - } - pos = th.startPos; - } else if (tc != null) { - pos = tc.startPos; - } - - final int fpos = pos; - new Timer().schedule(new TimerTask() { - @Override - public void run() { - if (fpos <= getDocument().getLength()) { - setCaretPosition(fpos); - } - } - }, 100); - } - } - - public DecompiledEditorPane(ABCPanel abcPanel) { - super(); - setEditable(false); - getCaret().setVisible(true); - addCaretListener(this); - this.abcPanel = abcPanel; - } - - public void clearScript() { - script = null; - } - - public void setScript(ScriptPack scriptLeaf, boolean force) { - if (!force && this.script == scriptLeaf) { - return; - } - String sn = scriptLeaf.getClassPath().toString(); - setScriptName(sn); - abcPanel.scriptNameLabel.setText(sn); - int scriptIndex = scriptLeaf.scriptIndex; - ScriptInfo nscript = null; - ABC abc = scriptLeaf.abc; - if (scriptIndex > -1) { - nscript = abc.script_info.get(scriptIndex); - } - if (nscript == null) { - highlights = new ArrayList<>(); - specialHighlights = new ArrayList<>(); - traitHighlights = new ArrayList<>(); - methodHighlights = new ArrayList<>(); - this.script = scriptLeaf; - return; - } - setText("// " + AppStrings.translate("pleasewait") + "..."); - - this.script = scriptLeaf; - CachedDecompilation cd = null; - try { - cd = SWF.getCached(scriptLeaf); - } catch (InterruptedException ex) { - } - - if (cd != null) { - String hilightedCode = cd.text; - highlights = cd.getInstructionHighlights(); - specialHighlights = cd.getSpecialHighligths(); - traitHighlights = cd.getTraitHighlights(); - methodHighlights = cd.getMethodHighlights(); - classHighlights = cd.getClassHighlights(); - setText(hilightedCode); - - if (classHighlights.size() > 0) { - try { - setCaretPosition(classHighlights.get(0).startPos); - } catch (Exception ex) { //sometimes happens - //ignore - } - } - } - fireScript(); - } - - public void reloadClass() { - int ci = classIndex; - SWF.uncache(script); - if (script != null && getABC() != null) { - setScript(script, true); - } - setNoTrait(); - setClassIndex(ci); - } - - public int getClassIndex() { - return classIndex; - } - - private ABC getABC() { - return script == null ? null : script.abc; - } - - @Override - public void setText(String t) { - super.setText(t); - setCaretPosition(0); - } -} +/* + * Copyright (C) 2010-2016 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.abc; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.CachedDecompilation; +import com.jpexs.decompiler.flash.abc.ScriptPack; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructSuperIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallSuperIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallSuperVoidIns; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; +import com.jpexs.decompiler.flash.abc.types.ClassInfo; +import com.jpexs.decompiler.flash.abc.types.InstanceInfo; +import com.jpexs.decompiler.flash.abc.types.Multiname; +import com.jpexs.decompiler.flash.abc.types.ScriptInfo; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction; +import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; +import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; +import com.jpexs.decompiler.flash.gui.AppStrings; +import com.jpexs.decompiler.flash.gui.View; +import com.jpexs.decompiler.flash.gui.editor.DebuggableEditorPane; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.helpers.hilight.HighlightData; +import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; +import com.jpexs.decompiler.flash.helpers.hilight.Highlighting; +import com.jpexs.decompiler.flash.tags.ABCContainerTag; +import com.jpexs.decompiler.graph.DottedChain; +import java.awt.Point; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; +import jsyntaxpane.SyntaxDocument; +import jsyntaxpane.Token; +import jsyntaxpane.TokenType; + +/** + * + * @author JPEXS + */ +public class DecompiledEditorPane extends DebuggableEditorPane implements CaretListener { + + private List highlights = new ArrayList<>(); + + private List specialHighlights = new ArrayList<>(); + + private List traitHighlights = new ArrayList<>(); + + private List methodHighlights = new ArrayList<>(); + + private List classHighlights = new ArrayList<>(); + + private Highlighting currentMethodHighlight; + + private Highlighting currentTraitHighlight; + + private ScriptPack script; + + public int lastTraitIndex = 0; + + public boolean ignoreCarret = false; + + private boolean reset = false; + + private final ABCPanel abcPanel; + + private int classIndex = -1; + + private boolean isStatic = false; + + private final List scriptListeners = new ArrayList<>(); + + public void addScriptListener(Runnable l) { + scriptListeners.add(l); + } + + public ABCPanel getAbcPanel() { + return abcPanel; + } + + public void removeScriptListener(Runnable l) { + scriptListeners.remove(l); + } + + public void fireScript() { + Runnable[] listeners = scriptListeners.toArray(new Runnable[scriptListeners.size()]); + for (Runnable scriptListener : listeners) { + scriptListener.run(); + } + } + + public Trait getCurrentTrait() { + return script.abc.findTraitByTraitId(classIndex, lastTraitIndex); + } + + public ScriptPack getScriptLeaf() { + return script; + } + + public boolean getIsStatic() { + return isStatic; + } + + public void setNoTrait() { + abcPanel.detailPanel.showCard(DetailPanel.UNSUPPORTED_TRAIT_CARD, null); + } + + public void hilightSpecial(HighlightSpecialType type, long index) { + int startPos; + int endPos; + if (currentMethodHighlight == null) { + if (currentTraitHighlight == null) { + return; + } + startPos = currentTraitHighlight.startPos; + endPos = currentTraitHighlight.startPos + currentTraitHighlight.len; + } else { + startPos = currentMethodHighlight.startPos; + endPos = currentMethodHighlight.startPos + currentMethodHighlight.len; + } + + List allh = new ArrayList<>(); + for (Highlighting h : traitHighlights) { + if (h.getProperties().index == lastTraitIndex) { + for (Highlighting sh : specialHighlights) { + if (sh.startPos >= h.startPos && (sh.startPos + sh.len < h.startPos + h.len)) { + allh.add(sh); + } + } + } + } + if (currentMethodHighlight != null) { + for (Highlighting h : specialHighlights) { + if (h.startPos >= startPos && (h.startPos + h.len < endPos)) { + allh.add(h); + } + } + } + for (Highlighting h : allh) { + if (h.getProperties().subtype.equals(type) && (h.getProperties().index == index)) { + ignoreCarret = true; + if (h.startPos <= getDocument().getLength()) { + setCaretPosition(h.startPos); + } + getCaret().setVisible(true); + ignoreCarret = false; + break; + } + } + } + + public void hilightOffset(long offset) { + if (currentMethodHighlight == null) { + return; + } + for (Highlighting h : traitHighlights) { + if (h.getProperties().index == lastTraitIndex) { + Highlighting h2 = Highlighting.searchOffset(highlights, offset, h.startPos, h.startPos + h.len); + if (h2 != null) { + ignoreCarret = true; + if (h2.startPos <= getDocument().getLength()) { + setCaretPosition(h2.startPos); + } + getCaret().setVisible(true); + ignoreCarret = false; + } + + } + } + } + + public void setClassIndex(int classIndex) { + this.classIndex = classIndex; + } + + private boolean displayMethod(int pos, int methodIndex, String name, Trait trait, boolean isStatic) { + ABC abc = getABC(); + if (abc == null) { + return false; + } + int bi = abc.findBodyIndex(methodIndex); + if (bi == -1) { + return false; + } + + //fix for inner functions: + if (trait instanceof TraitMethodGetterSetter) { + TraitMethodGetterSetter tm = (TraitMethodGetterSetter) trait; + if (tm.method_info != methodIndex) { + trait = null; + } + } + if (trait instanceof TraitFunction) { + TraitFunction tf = (TraitFunction) trait; + if (tf.method_info != methodIndex) { + trait = null; + } + } + abcPanel.detailPanel.showCard(DetailPanel.METHOD_TRAIT_CARD, trait); + MethodCodePanel methodCodePanel = abcPanel.detailPanel.methodTraitPanel.methodCodePanel; + if (reset || (methodCodePanel.getBodyIndex() != bi)) { + methodCodePanel.setBodyIndex(scriptName, bi, abc, name, trait, script.scriptIndex); + abcPanel.detailPanel.setEditMode(false); + this.isStatic = isStatic; + } + boolean success = false; + Highlighting h = Highlighting.searchPos(highlights, pos); + if (h != null) { + methodCodePanel.hilighOffset(h.getProperties().offset); + success = true; + } + Highlighting sh = Highlighting.searchPos(specialHighlights, pos); + if (sh != null) { + methodCodePanel.hilighSpecial(sh.getProperties().subtype, sh.getProperties().specialValue); + success = true; + } + return success; + } + + public void displayClass(int classIndex, int scriptIndex) { + if (abcPanel.navigator.getClassIndex() != classIndex) { + abcPanel.navigator.setClassIndex(classIndex, scriptIndex); + } + } + + public void resetEditing() { + reset = true; + caretUpdate(null); + reset = false; + } + + public int getMultinameUnderMouseCursor(Point pt) { + return getMultinameAtPos(viewToModel(pt)); + } + + public int getMultinameUnderCaret() { + return getMultinameAtPos(getCaretPosition()); + } + + public int getLocalDeclarationOfPos(int pos, Reference type) { + Highlighting sh = Highlighting.searchPos(specialHighlights, pos); + Highlighting h = Highlighting.searchPos(highlights, pos); + + if (h == null) { + return -1; + } + + List tms = Highlighting.searchAllPos(methodHighlights, pos); + if (tms.isEmpty()) { + return -1; + } + for (Highlighting tm : tms) { + + List tm_tms = Highlighting.searchAllIndexes(methodHighlights, tm.getProperties().index); + //is it already declaration? + if (h.getProperties().declaration || (sh != null && sh.getProperties().declaration)) { + return -1; //no jump + } + + String lname = h.getProperties().localName; + if ("this".equals(lname)) { + Highlighting ch = Highlighting.searchPos(classHighlights, pos); + int cindex = (int) ch.getProperties().index; + ABC abc = getABC(); + type.setVal(abc.instance_info.get(cindex).getName(abc.constants).getNameWithNamespace(abc.constants)); + return ch.startPos; + } + + HighlightData hData = h.getProperties(); + HighlightData search = new HighlightData(); + search.declaration = hData.declaration; + search.declaredType = hData.declaredType; + search.localName = hData.localName; + search.specialValue = hData.specialValue; + if (search.isEmpty()) { + return -1; + } + search.declaration = true; + + for (Highlighting tm1 : tm_tms) { + Highlighting rh = Highlighting.search(highlights, search, tm1.startPos, tm1.startPos + tm1.len); + if (rh == null) { + rh = Highlighting.search(specialHighlights, search, tm1.startPos, tm1.startPos + tm1.len); + } + if (rh != null) { + type.setVal(rh.getProperties().declaredType); + return rh.startPos; + } + } + } + + return -1; + } + + public boolean getPropertyTypeAtPos(int pos, Reference abcIndex, Reference classIndex, Reference traitIndex, Reference classTrait, Reference multinameIndex) { + + int m = getMultinameAtPos(pos, true); + if (m <= 0) { + return false; + } + SyntaxDocument sd = (SyntaxDocument) getDocument(); + Token t = sd.getTokenAt(pos + 1); + Token lastToken = t; + Token prev; + while (t.type == TokenType.IDENTIFIER || t.type == TokenType.KEYWORD || t.type == TokenType.REGEX) { + prev = sd.getPrevToken(t); + if (prev != null) { + if (!".".equals(prev.getString(sd))) { + break; + } + t = sd.getPrevToken(prev); + } else { + break; + } + } + if (t.type != TokenType.IDENTIFIER && t.type != TokenType.KEYWORD || t.type == TokenType.REGEX) { + return false; + } + Reference locTypeRef = new Reference<>(DottedChain.EMPTY); + getLocalDeclarationOfPos(t.start, locTypeRef); + DottedChain currentType = locTypeRef.getVal(); + if (currentType.equals(DottedChain.ALL)) { + return false; + } + boolean found; + t = sd.getNextToken(t); + while (t != lastToken && !currentType.equals(DottedChain.ALL)) { + t = sd.getNextToken(t); + String ident = t.getString(sd); + found = false; + List abcList = getABC().getSwf().getAbcList(); + loopi: + for (int i = 0; i < abcList.size(); i++) { + ABC a = abcList.get(i).getABC(); + int cindex = a.findClassByName(currentType); + if (cindex > -1) { + InstanceInfo ii = a.instance_info.get(cindex); + for (int j = 0; j < ii.instance_traits.traits.size(); j++) { + Trait tr = ii.instance_traits.traits.get(j); + if (ident.equals(tr.getName(a).getName(a.constants, null, false /*NOT RAW!*/))) { + classIndex.setVal(cindex); + abcIndex.setVal(i); + traitIndex.setVal(j); + classTrait.setVal(false); + multinameIndex.setVal(tr.name_index); + currentType = ii.getName(a.constants).getNameWithNamespace(a.constants); + found = true; + break loopi; + } + } + + ClassInfo ci = a.class_info.get(cindex); + for (int j = 0; j < ci.static_traits.traits.size(); j++) { + Trait tr = ci.static_traits.traits.get(j); + if (ident.equals(tr.getName(a).getName(a.constants, null, false /*NOT RAW!*/))) { + classIndex.setVal(cindex); + abcIndex.setVal(i); + traitIndex.setVal(j); + classTrait.setVal(true); + multinameIndex.setVal(tr.name_index); + currentType = ii.getName(a.constants).getNameWithNamespace(a.constants); + found = true; + break loopi; + } + } + } + } + if (!found) { + return false; + } + + t = sd.getNextToken(t); + if (!".".equals(t.getString(sd))) { + break; + } + } + return true; + } + + public int getMultinameAtPos(int pos) { + return getMultinameAtPos(pos, false); + } + + private int getMultinameAtPos(int pos, boolean codeOnly) { + int multinameIndex = _getMultinameAtPos(pos, codeOnly); + if (multinameIndex > -1) { + ABC abc = getABC(); + multinameIndex = abc.constants.convertToQname(abc.constants, multinameIndex); + } + return multinameIndex; + } + + public int _getMultinameAtPos(int pos, boolean codeOnly) { + Highlighting tm = Highlighting.searchPos(methodHighlights, pos); + Trait currentTrait = null; + int currentMethod = -1; + ABC abc = getABC(); + if (tm != null) { + + int mi = (int) tm.getProperties().index; + currentMethod = mi; + int bi = abc.findBodyIndex(mi); + Highlighting h = Highlighting.searchPos(highlights, pos); + if (h != null) { + long highlightOffset = h.getProperties().offset; + List list = abc.bodies.get(bi).getCode().code; + AVM2Instruction lastIns = null; + AVM2Instruction selIns = null; + for (AVM2Instruction ins : list) { + if (highlightOffset == ins.getAddress()) { + selIns = ins; + break; + } + if (ins.getAddress() > highlightOffset) { + selIns = lastIns; + break; + } + lastIns = ins; + } + if (selIns != null) { + //long inspos = highlightOffset - selIns.offset; + if (!codeOnly && ((selIns.definition instanceof ConstructSuperIns) || (selIns.definition instanceof CallSuperIns) || (selIns.definition instanceof CallSuperVoidIns))) { + Highlighting tc = Highlighting.searchPos(classHighlights, pos); + if (tc != null) { + int cindex = (int) tc.getProperties().index; + if (cindex > -1) { + return abc.instance_info.get(cindex).super_index; + } + } + } else { + for (int i = 0; i < selIns.definition.operands.length; i++) { + if (selIns.definition.operands[i] == AVM2Code.DAT_MULTINAME_INDEX) { + return selIns.operands[i]; + } + } + } + } + } + + } + if (codeOnly) { + return -1; + } + + Highlighting ch = Highlighting.searchPos(classHighlights, pos); + if (ch != null) { + Highlighting th = Highlighting.searchPos(traitHighlights, pos); + if (th != null) { + currentTrait = abc.findTraitByTraitId((int) ch.getProperties().index, (int) th.getProperties().index); + } + } + + if (currentTrait instanceof TraitMethodGetterSetter) { + currentMethod = ((TraitMethodGetterSetter) currentTrait).method_info; + } + Highlighting sh = Highlighting.searchPos(specialHighlights, pos); + if (sh != null) { + switch (sh.getProperties().subtype) { + case TYPE_NAME: + String typeName = sh.getProperties().specialValue; + for (int i = 1; i < abc.constants.getMultinameCount(); i++) { + Multiname m = abc.constants.getMultiname(i); + if (m != null) { + if (typeName.equals(m.getNameWithNamespace(abc.constants).toRawString())) { + return i; + } + } + } + case TRAIT_TYPE_NAME: + if (currentTrait instanceof TraitSlotConst) { + TraitSlotConst ts = (TraitSlotConst) currentTrait; + return ts.type_index; + } + break; + case TRAIT_NAME: + if (currentTrait != null) { + //return currentTrait.name_index; + } + break; + case RETURNS: + if (currentMethod > -1) { + return abc.method_info.get(currentMethod).ret_type; + } + break; + case PARAM: + if (currentMethod > -1) { + return abc.method_info.get(currentMethod).param_types[(int) sh.getProperties().index]; + } + break; + } + } + return -1; + } + + @Override + public void caretUpdate(final CaretEvent e) { + ABC abc = getABC(); + if (abc == null) { + return; + } + if (ignoreCarret) { + return; + } + + getCaret().setVisible(true); + int pos = getCaretPosition(); + abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setIgnoreCarret(true); + try { + classIndex = -1; + Highlighting cm = Highlighting.searchPos(classHighlights, pos); + if (cm != null) { + classIndex = (int) cm.getProperties().index; + } + displayClass(classIndex, script.scriptIndex); + Highlighting tm = Highlighting.searchPos(methodHighlights, pos); + if (tm != null) { + String name = ""; + if (classIndex > -1) { + name = abc.instance_info.get(classIndex).getName(abc.constants).getNameWithNamespace(abc.constants).toPrintableString(true); + } + + Trait currentTrait = null; + currentTraitHighlight = Highlighting.searchPos(traitHighlights, pos); + if (currentTraitHighlight != null) { + lastTraitIndex = (int) currentTraitHighlight.getProperties().index; + if (classIndex != -1) { + currentTrait = getCurrentTrait(); + isStatic = abc.isStaticTraitId(classIndex, lastTraitIndex); + if (currentTrait != null) { + name += ":" + currentTrait.getName(abc).getName(abc.constants, null, false); + } + } + } + + displayMethod(pos, (int) tm.getProperties().index, name, currentTrait, isStatic); + currentMethodHighlight = tm; + return; + } + + if (classIndex == -1) { + abcPanel.navigator.setClassIndex(-1, script.scriptIndex); + setNoTrait(); + return; + } + Trait currentTrait; + currentTraitHighlight = Highlighting.searchPos(traitHighlights, pos); + if (currentTraitHighlight != null) { + lastTraitIndex = (int) currentTraitHighlight.getProperties().index; + currentTrait = getCurrentTrait(); + if (currentTrait != null) { + if (currentTrait instanceof TraitSlotConst) { + abcPanel.detailPanel.slotConstTraitPanel.load((TraitSlotConst) currentTrait, abc, + abc.isStaticTraitId(classIndex, lastTraitIndex)); + final Trait ftrait = currentTrait; + View.execInEventDispatch(() -> { + abcPanel.detailPanel.showCard(DetailPanel.SLOT_CONST_TRAIT_CARD, ftrait); + }); + abcPanel.detailPanel.setEditMode(false); + currentMethodHighlight = null; + Highlighting spec = Highlighting.searchPos(specialHighlights, pos, currentTraitHighlight.startPos, currentTraitHighlight.startPos + currentTraitHighlight.len); + if (spec != null) { + abcPanel.detailPanel.slotConstTraitPanel.hilightSpecial(spec); + } + + return; + } + } + currentMethodHighlight = null; + //currentTrait = null; + String name = abc.instance_info.get(classIndex).getName(abc.constants).getNameWithNamespace(abc.constants).toPrintableString(true); + currentTrait = getCurrentTrait(); + isStatic = abc.isStaticTraitId(classIndex, lastTraitIndex); + if (currentTrait != null) { + name += ":" + currentTrait.getName(abc).getName(abc.constants, null, false); + } + + displayMethod(pos, abc.findMethodIdByTraitId(classIndex, lastTraitIndex), name, currentTrait, isStatic); + return; + } + setNoTrait(); + } finally { + abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setIgnoreCarret(false); + } + } + + public void gotoLastTrait() { + gotoTrait(lastTraitIndex); + } + + public void gotoTrait(int traitId) { + boolean isScriptInit = traitId == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER; + + Highlighting tc = Highlighting.searchIndex(classHighlights, classIndex); + if (tc != null || isScriptInit) { + Highlighting th = Highlighting.searchIndex(traitHighlights, traitId, isScriptInit || tc == null ? 0 : tc.startPos, isScriptInit || tc == null ? -1 : tc.startPos + tc.len); + int pos = 0; + if (th != null) { + if (th.len > 1) { + ignoreCarret = true; + int startPos = th.startPos + th.len - 1; + if (startPos <= getDocument().getLength()) { + setCaretPosition(startPos); + } + ignoreCarret = false; + } + pos = th.startPos; + } else if (tc != null) { + pos = tc.startPos; + } + + final int fpos = pos; + new Timer().schedule(new TimerTask() { + @Override + public void run() { + if (fpos <= getDocument().getLength()) { + setCaretPosition(fpos); + } + } + }, 100); + } + } + + public DecompiledEditorPane(ABCPanel abcPanel) { + super(); + setEditable(false); + getCaret().setVisible(true); + addCaretListener(this); + this.abcPanel = abcPanel; + } + + public void clearScript() { + script = null; + } + + public void setScript(ScriptPack scriptLeaf, boolean force) { + if (!force && this.script == scriptLeaf) { + return; + } + String sn = scriptLeaf.getClassPath().toString(); + setScriptName(sn); + abcPanel.scriptNameLabel.setText(sn); + int scriptIndex = scriptLeaf.scriptIndex; + ScriptInfo nscript = null; + ABC abc = scriptLeaf.abc; + if (scriptIndex > -1) { + nscript = abc.script_info.get(scriptIndex); + } + if (nscript == null) { + highlights = new ArrayList<>(); + specialHighlights = new ArrayList<>(); + traitHighlights = new ArrayList<>(); + methodHighlights = new ArrayList<>(); + this.script = scriptLeaf; + return; + } + setText("// " + AppStrings.translate("pleasewait") + "..."); + + this.script = scriptLeaf; + CachedDecompilation cd = null; + try { + cd = SWF.getCached(scriptLeaf); + } catch (InterruptedException ex) { + } + + if (cd != null) { + String hilightedCode = cd.text; + highlights = cd.getInstructionHighlights(); + specialHighlights = cd.getSpecialHighligths(); + traitHighlights = cd.getTraitHighlights(); + methodHighlights = cd.getMethodHighlights(); + classHighlights = cd.getClassHighlights(); + setText(hilightedCode); + + if (classHighlights.size() > 0) { + try { + setCaretPosition(classHighlights.get(0).startPos); + } catch (Exception ex) { //sometimes happens + //ignore + } + } + } + fireScript(); + } + + public void reloadClass() { + int ci = classIndex; + SWF.uncache(script); + if (script != null && getABC() != null) { + setScript(script, true); + } + setNoTrait(); + setClassIndex(ci); + } + + public int getClassIndex() { + return classIndex; + } + + private ABC getABC() { + return script == null ? null : script.abc; + } + + @Override + public void setText(String t) { + super.setText(t); + setCaretPosition(0); + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/abc/TraitsList.java b/src/com/jpexs/decompiler/flash/gui/abc/TraitsList.java index 7c63a7498..64cddc25d 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/TraitsList.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/TraitsList.java @@ -1,101 +1,101 @@ -/* - * Copyright (C) 2010-2016 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.abc; - -import com.jpexs.decompiler.flash.abc.ABC; -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Graphics2D; -import javax.swing.DefaultListModel; -import javax.swing.JList; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; - -/** - * - * @author JPEXS - */ -public class TraitsList extends JList implements ListSelectionListener { - - private ABC abc; - - private int classIndex = -1; - - private final ABCPanel abcPanel; - - private boolean sorted = false; - - public void setSorted(boolean sorted) { - if (getModel() instanceof TraitsListModel) { - ((TraitsListModel) getModel()).setSorted(sorted); - } - this.sorted = sorted; - } - - public int getClassIndex() { - return classIndex; - } - - public TraitsList(ABCPanel abcPanel) { - addListSelectionListener(this); - this.abcPanel = abcPanel; - setCellRenderer(new IconListRenderer()); - //setUI(new BasicListUI()); - setBackground(Color.white); - } - - public void clearAbc() { - this.abc = null; - setModel(new DefaultListModel<>()); - } - - public void setAbc(ABC abc) { - this.abc = abc; - setModel(new DefaultListModel<>()); - setClassIndex(-1, -1); - } - - public void setClassIndex(int classIndex, int scriptIndex) { - if (classIndex >= abc.instance_info.size()) { - return; - } - this.classIndex = classIndex; - setModel(new TraitsListModel(abc, classIndex, scriptIndex, sorted)); - - } - - private int lastSelected = -1; - - @Override - public void valueChanged(ListSelectionEvent e) { - if (getSelectedIndex() == lastSelected) { - return; - } - lastSelected = getSelectedIndex(); - TraitsListItem sel = (TraitsListItem) getSelectedValue(); - abcPanel.decompiledTextArea.gotoTrait(sel == null ? -1 : sel.getGlobalTraitId()); - - } - - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - g2d.setComposite(AlphaComposite.SrcOver); - super.paint(g); - } -} +/* + * Copyright (C) 2010-2016 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.abc; + +import com.jpexs.decompiler.flash.abc.ABC; +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import javax.swing.DefaultListModel; +import javax.swing.JList; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +/** + * + * @author JPEXS + */ +public class TraitsList extends JList implements ListSelectionListener { + + private ABC abc; + + private int classIndex = -1; + + private final ABCPanel abcPanel; + + private boolean sorted = false; + + public void setSorted(boolean sorted) { + if (getModel() instanceof TraitsListModel) { + ((TraitsListModel) getModel()).setSorted(sorted); + } + this.sorted = sorted; + } + + public int getClassIndex() { + return classIndex; + } + + public TraitsList(ABCPanel abcPanel) { + addListSelectionListener(this); + this.abcPanel = abcPanel; + setCellRenderer(new IconListRenderer()); + //setUI(new BasicListUI()); + setBackground(Color.white); + } + + public void clearAbc() { + this.abc = null; + setModel(new DefaultListModel<>()); + } + + public void setAbc(ABC abc) { + this.abc = abc; + setModel(new DefaultListModel<>()); + setClassIndex(-1, -1); + } + + public void setClassIndex(int classIndex, int scriptIndex) { + if (classIndex >= abc.instance_info.size()) { + return; + } + this.classIndex = classIndex; + setModel(new TraitsListModel(abc, classIndex, scriptIndex, sorted)); + + } + + private int lastSelected = -1; + + @Override + public void valueChanged(ListSelectionEvent e) { + if (getSelectedIndex() == lastSelected) { + return; + } + lastSelected = getSelectedIndex(); + TraitsListItem sel = (TraitsListItem) getSelectedValue(); + abcPanel.decompiledTextArea.gotoTrait(sel == null ? -1 : sel.getGlobalTraitId()); + + } + + @Override + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setComposite(AlphaComposite.SrcOver); + super.paint(g); + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AboutDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/AboutDialog.properties index 1db9944e5..65134b742 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AboutDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AboutDialog.properties @@ -1,27 +1,27 @@ -# Copyright (C) 2010-2016 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 . - -version = version -by = by -button.ok = OK -dialog.title = About -contributors = Contributors: -#In the translation, replace "english" with target language name -translation.author.label = Author of english translation: -#In the translation, insert your name here -translation.author = JPEXS -developers = Developers: -developers.others = + others from GitHub and Google code -translators = Translators: +# Copyright (C) 2010-2016 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 . + +version = version +by = by +button.ok = OK +dialog.title = About +contributors = Contributors: +#In the translation, replace "english" with target language name +translation.author.label = Author of english translation: +#In the translation, insert your name here +translation.author = JPEXS +developers = Developers: +developers.others = + others from GitHub and Google code +translators = Translators: diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AboutDialog_es.properties b/src/com/jpexs/decompiler/flash/gui/locales/AboutDialog_es.properties index 7c5c198ae..5ff1527e5 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AboutDialog_es.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AboutDialog_es.properties @@ -1,27 +1,27 @@ -# Copyright (C) 2010-2016 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 . - -version = versi\u00f3n -by = por -button.ok = OK -dialog.title = Acerca de -contributors = Colaboradores: -#In the translation, replace "english" with target language name -translation.author.label = Autor de la traducci\u00f3n al espa\u00f1ol: -#In the translation, insert your name here -translation.author = poxyran -developers = Desarrolladores: -developers.others = + otros de GitHub y Google code -translators = Traductores: +# Copyright (C) 2010-2016 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 . + +version = versi\u00f3n +by = por +button.ok = OK +dialog.title = Acerca de +contributors = Colaboradores: +#In the translation, replace "english" with target language name +translation.author.label = Autor de la traducci\u00f3n al espa\u00f1ol: +#In the translation, insert your name here +translation.author = poxyran +developers = Desarrolladores: +developers.others = + otros de GitHub y Google code +translators = Traductores: diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AboutDialog_sv.properties b/src/com/jpexs/decompiler/flash/gui/locales/AboutDialog_sv.properties index 00a0f47e9..ca3f77e85 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AboutDialog_sv.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AboutDialog_sv.properties @@ -1,27 +1,27 @@ -# Copyright (C) 2010-2016 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 . - -version = version -by = av -button.ok = Okej -dialog.title = Om -contributors = Bidragande: -#In the translation, replace "english" with target language name -translation.author.label = Skapare utav Svensk \u00f6vers\u00e4ttning: -#In the translation, insert your name here -translation.author = Capasha -developers = Utvecklare: -developers.others = + andra fr\u00e5n GitHub och Google code -translators = \u00d6vers\u00e4ttare: +# Copyright (C) 2010-2016 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 . + +version = version +by = av +button.ok = Okej +dialog.title = Om +contributors = Bidragande: +#In the translation, replace "english" with target language name +translation.author.label = Skapare utav Svensk \u00f6vers\u00e4ttning: +#In the translation, insert your name here +translation.author = Capasha +developers = Utvecklare: +developers.others = + andra fr\u00e5n GitHub och Google code +translators = \u00d6vers\u00e4ttare: diff --git a/src/com/jpexs/decompiler/flash/gui/locales/LoadFromCacheFrame_fr.properties b/src/com/jpexs/decompiler/flash/gui/locales/LoadFromCacheFrame_fr.properties index 622d225e5..0bd5307a7 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/LoadFromCacheFrame_fr.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/LoadFromCacheFrame_fr.properties @@ -1,21 +1,21 @@ -# Copyright (C) 2010-2016 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 . - -button.open = Ouvrir -button.save = Enregistrer -button.refresh = Rafra\u00eechir la liste -dialog.title = Rechercher dans la m\u00e9moire cache des navigateurs -supported.browsers = Navigateurs support\u00e9s : -info.closed = *Ce navigateur conserve les donn\u00e9es sur le disque en cache apr\u00e8s fermeture. +# Copyright (C) 2010-2016 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 . + +button.open = Ouvrir +button.save = Enregistrer +button.refresh = Rafra\u00eechir la liste +dialog.title = Rechercher dans la m\u00e9moire cache des navigateurs +supported.browsers = Navigateurs support\u00e9s : +info.closed = *Ce navigateur conserve les donn\u00e9es sur le disque en cache apr\u00e8s fermeture. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_es.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_es.properties index c494a23fc..c7ba4cc8b 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_es.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_es.properties @@ -1,719 +1,721 @@ -# Copyright (C) 2010-2016 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 . - -menu.file = Archivo -menu.file.open = Abrir... -menu.file.save = Guardar -menu.file.saveas = Guardar como... -menu.file.export.fla = Exportar a FLA -menu.file.export.all = Exportar todas las partes -menu.file.export.selection = Exportar selecci\u00f3n -menu.file.exit = Salir - -menu.tools = Herramientas -menu.tools.searchas = Buscar todo el ActionScript... -menu.tools.proxy = Proxy -menu.tools.deobfuscation = Desofuscaci\u00f3n -menu.tools.deobfuscation.pcode = Desofuscaci\u00f3n de PCode... -menu.tools.deobfuscation.globalrename = Renombrar identificador globalmente -menu.tools.deobfuscation.renameinvalid = Renombrar identificadores inv\u00e1lidos -menu.tools.gotoDocumentClass = Ir al document class - -menu.settings = Ajustes -menu.settings.autodeobfuscation = Desofuscaci\u00f3n autom\u00e1tica -menu.settings.internalflashviewer = Usar un visor de flash propio -menu.settings.parallelspeedup = Aceleraci\u00f3n en paralelo -menu.settings.disabledecompilation = Inhabilitar decompilaci\u00f3n (solo desensamblado) -menu.settings.addtocontextmenu = Agregar FFDec al men\u00fa contextual de archivos SWF -menu.settings.language = Cambiar lenguaje -menu.settings.cacheOnDisk = Usar almacenamiento de cach\u00e9 en disco -menu.settings.gotoMainClassOnStartup = Resaltar el document class al iniciar - -menu.help = Ayuda -menu.help.checkupdates = Comprobar actualizaciones... -menu.help.helpus = Ayudanos! -menu.help.homepage = Visitar la p\u00e1gina principal -menu.help.about = Acerca de... - -contextmenu.remove = Remover - -button.save = Guardar -button.edit = Editar -button.cancel = Cancelar -button.replace = Reemplazar... - -notavailonthisplatform = La vista previa de este objeto no est\u00e1 disponible en esta plataforma. (solo Windows) - -swfpreview = Vista previa del SWF -swfpreview.internal = Vista previa del SWF (Visor interno) - -parameters = Par\u00e1metros - -rename.enternew = Ingresar nuevo nombre: - -rename.finished.identifier = Identificador renombrado. -rename.finished.multiname = %count% multinombres(s) renombrado. - -node.texts = textos -node.images = im\u00e1genes -node.movies = pel\u00edculas -node.sounds = sonidos -node.binaryData = datosbinarios -node.fonts = fuentes -node.sprites = sprites -node.shapes = formas -node.morphshapes = morphshapes -node.buttons = botones -node.frames = marcos -node.scripts = scripts - -message.warning = Cuidado -message.confirm.experimental = El siguiente procedimiento puede da\u00f1ar el archivo SWF e inutilizar su reproducci\u00f3n.\r\nUSESE BAJO SU PROPIO RIESGO. Desea continuar? -message.confirm.parallel = El paralelismo puede acelerar la carga y la descompilaci\u00f3n pero requerir m\u00e1s memoria. -message.confirm.on = Desea encenderlo? -message.confirm.off = Desea apagarlo? -message.confirm = Confirmar - -message.confirm.autodeobfuscate = La desofuscaci\u00f3n autom\u00e1tica es una manera de descompilar el c\u00f3digo ofuscado.\r\nLa desofuscaci\u00f3n conduce a una descompilaci\u00f3n m\u00e1s lenta y a eliminar algo de c\u00f3digo muerto.\r\nSi el c\u00f3digo no est\u00e1 ofuscado, es mejor deshabilitar la autodesofuscaci\u00f3n. - -message.parallel = Paralelismo -message.trait.saved = Rasgo guardado existosamente - -message.constant.new.string = La cadena "%value%" no est\u00e1 presente en la tabla de constantes. Desea agregarla? -message.constant.new.string.title = Agregar cadena -message.constant.new.integer = El entero "%value%" no est\u00e1 presente en la tabla de constantes. Desea agregarlo? -message.constant.new.integer.title = Agregar entero -message.constant.new.unsignedinteger = El entero no signado "%value%" no est\u00e1 presente en la tabla de constantes. Desea agregarlo? -message.constant.new.unsignedinteger.title = Agregar entero no signado -message.constant.new.double = El entero doble "%value%" no est\u00e1 presente en la tabla de constantes. Desea agregarlo? -message.constant.new.double.title = Agregar entero doble - -work.buffering = Buffering -work.waitingfordissasembly = Esperando el desensamblado -work.gettinghilights = Adquiriendo resaltadores -work.disassembling = Desensamblando -work.exporting = Exportando -work.searching = Buscando -work.renaming = Renombrando -work.exporting.fla = Exportando FLA -work.renaming.identifiers = Renombrando identificadores -work.deobfuscating = Desofuscando -work.decompiling = Decompilando -work.gettingvariables = Adquiriendo variables -work.reading.swf = Leyendo SWF -work.creatingwindow = Creando ventana -work.buildingscripttree = Generando \u00e1rbol de script Building script tree - -work.deobfuscating.complete = Desofuscaci\u00f3n completada - -message.search.notfound = Cadena "%searchtext%" no encontrada. -message.search.notfound.title = No encontrado - -message.rename.notfound.multiname = No se encontr\u00f3 ning\u00fan multiname bajo el cursor -message.rename.notfound.identifier = No se encontr\u00f3 ning\u00fan identificador bajo el cursor -message.rename.notfound.title = No encontrado -message.rename.renamed = Identificadores renombrados: %count% - -filter.images = Im\u00e1genes (%extensions%) -filter.fla = Documento %version% (*.fla) -filter.xfl = Documento no comprimido %version% (*.xfl) -filter.swf = Archivos SWF (*.swf) - -error = Error -error.image.invalid = Im\u00e1gen inv\u00e1lida. - -error.text.invalid = Texto inv\u00e1lido: %text% en la l\u00ednea %line% -error.file.save = No se puede guardar el archivo -error.file.write = No se puede escribir al archivo -error.export = Error durante la exportaci\u00f3n - -export.select.directory = Seleccione directorio para exportar -export.finishedin = Exportado en %time% - -update.check.title = Chequeo de actualizaci\u00f3n -update.check.nonewversion = No hay versi\u00f3n nueva disponible. - -message.helpus = Por favor, visite\r\n%url%\r\npara m\u00e1s detalles. -message.homepage = Visite la p\u00e1gina principal en: \r\n%url% - -proxy = Proxy -proxy.start = Comenzar proxy -proxy.stop = Detener proxy -proxy.show = Mostrar proxy -exit = Salir - -panel.disassembled = Fuente P-code -panel.decompiled = Fuente ActionScript - -search.info = Buscar por "%text%" : -search.script = Script - -constants = Constantes -traits = Rasgos - -pleasewait = Espere por favor - -abc.detail.methodtrait = M\u00e9todo/Getter/Setter Rasgo -abc.detail.unsupported = - -abc.detail.slotconsttrait = Slot/Const Rasgo -abc.detail.traitname = Nombre: - -abc.detail.body.params.maxstack = Pila m\u00e1xima: -abc.detail.body.params.localregcount = Contador de registros locales: -abc.detail.body.params.minscope = Profundidad de alcance m\u00ednima: -abc.detail.body.params.maxscope = Profundidad de alcance m\u00e1xima: -abc.detail.body.params.autofill = Auto rellenado al salvar c\u00f3dig (AJUSTE GLOBAL) -abc.detail.body.params.autofill.experimental = ...EXPERIMENTAL - -abc.detail.methodinfo.methodindex = Indice de m\u00e9todo: -abc.detail.methodinfo.parameters = Par\u00e1metros: -abc.detail.methodinfo.returnvalue = Tipo de valor de retorno: - -error.methodinfo.params = Error de pa\u0155ametro MethodInfo -error.methodinfo.returnvalue = Error de retorno de tipo MethodInfo - -abc.detail.methodinfo = MethodInfo -abc.detail.body.code = C\u00f3digo de MethodBody -abc.detail.body.params = Par\u00e1metros de MethodBody - -abc.detail.slotconst.typevalue = Tipo y valor: - -error.slotconst.typevalue = Error de valor de tipo SlotConst - -message.autofill.failed = No se puede obtener las estad\u00edsticas de c\u00f3digo para los par\u00e1metros de cuerpo autom\u00e1ticos.\r\nDestilde auto-llenado para evitar este mensaje. -info.selecttrait = Seleccione la clase y clickee un atributo en el c\u00f3digo Actionscript para editarlo. - -button.viewgraph = Ver grafo -button.viewhex = Ver en hexa - -abc.traitslist.instanceinitializer = inicializador de instancia -abc.traitslist.classinitializer = inicializador de clase - -action.edit.experimental = (Experimental) - -message.action.saved = C\u00f3digo guardado exitosamente - -error.action.save = %error% en la l\u00ednea %line% - -message.confirm.remove = Est\u00e1 seguro que desea remover %item% \n y todos los objetos que dependen de \u00e9l? - -#after version 1.6.5u1: - -button.ok = OK -button.cancel = Cancelar - -font.name = Nombre de fuente: -font.isbold = Es negrita: -font.isitalic = Es it\u00e1lica: -font.ascent = Ascendente: -font.descent = Descendente: -font.leading = Destacado: -font.characters = Caract\u00e9r: -font.characters.add = Agregar caracteres: -value.unknown = ? - -yes = si -no = no - -errors.present = Hay ERRORES en el log. Clickear para ver. -errors.none = No hay errores en el log - -#after version 1.6.6: - -dialog.message.title = Mensaje -dialog.select.title = Seleccione una opci\u00f3n - -button.yes = Si -button.no = No - -FileChooser.openButtonText = Abrir -FileChooser.openButtonToolTipText = Abrir -FileChooser.lookInLabelText = Mirar en: -FileChooser.acceptAllFileFilterText = Todos los archivos -FileChooser.filesOfTypeLabelText = Archivos de tipo: -FileChooser.fileNameLabelText = Nombre de archivo: -FileChooser.listViewButtonToolTipText = Lista -FileChooser.listViewButtonAccessibleName = Lista -FileChooser.detailsViewButtonToolTipText = Detales -FileChooser.detailsViewButtonAccessibleName = Detalles -FileChooser.upFolderToolTipText = Subir un nivel -FileChooser.upFolderAccessibleName = Subir un nivel -FileChooser.homeFolderToolTipText = Home -FileChooser.homeFolderAccessibleName = Home -FileChooser.fileNameHeaderText = Nombre -FileChooser.fileSizeHeaderText = Tama\u00f1o -FileChooser.fileTypeHeaderText = Tipo -FileChooser.fileDateHeaderText = Fecha -FileChooser.fileAttrHeaderText = Atributos -FileChooser.openDialogTitleText = Abrir -FileChooser.directoryDescriptionText = Directorio -FileChooser.directoryOpenButtonText = Abrir -FileChooser.directoryOpenButtonToolTipText = Abrir el directorio seleccionado -FileChooser.fileDescriptionText = Archivo gen\u00e9rico -FileChooser.helpButtonText = Ayuda -FileChooser.helpButtonToolTipText = Ayuda de FileChooser -FileChooser.newFolderAccessibleName = Nueva carpeta -FileChooser.newFolderErrorText = Error creando nueva carpeta -FileChooser.newFolderToolTipText = Crear nueva carpeta -FileChooser.other.newFolder = NuevaCarpeta -FileChooser.other.newFolder.subsequent = NuevaCarpeta.{0} -FileChooser.win32.newFolder = Nueva Carpeta -FileChooser.win32.newFolder.subsequent = Nueva Carpeta ({0}) -FileChooser.saveButtonText = Guarda -FileChooser.saveButtonToolTipText = Guardar archivo seleccionado -FileChooser.saveDialogTitleText = Guardar -FileChooser.saveInLabelText = Guardar en: -FileChooser.updateButtonText = Actualizar -FileChooser.updateButtonToolTipText = Actualizar listado de directorio - -#after version 1.6.6u2: - -FileChooser.detailsViewActionLabel.textAndMnemonic = Detalles -FileChooser.detailsViewButtonToolTip.textAndMnemonic = Detalles -FileChooser.fileAttrHeader.textAndMnemonic = Atributos -FileChooser.fileDateHeader.textAndMnemonic = Modificado -FileChooser.fileNameHeader.textAndMnemonic = Nombre -FileChooser.fileNameLabel.textAndMnemonic = Nombre de archivo: -FileChooser.fileSizeHeader.textAndMnemonic = Tama\u00f1o -FileChooser.fileTypeHeader.textAndMnemonic = Tipo -FileChooser.filesOfTypeLabel.textAndMnemonic = Archivos de tipo: -FileChooser.folderNameLabel.textAndMnemonic = Nombre de carpeta: -FileChooser.homeFolderToolTip.textAndMnemonic = Home -FileChooser.listViewActionLabel.textAndMnemonic = Lista -FileChooser.listViewButtonToolTip.textAndMnemonic = Lista -FileChooser.lookInLabel.textAndMnemonic = Mirar en: -FileChooser.newFolderActionLabel.textAndMnemonic = Nueva Carpeta -FileChooser.newFolderToolTip.textAndMnemonic = Crear Nueva Carpeta -FileChooser.refreshActionLabel.textAndMnemonic = Refrescar -FileChooser.saveInLabel.textAndMnemonic = Guardar en: -FileChooser.upFolderToolTip.textAndMnemonic = Subir un nivel -FileChooser.viewMenuButtonAccessibleName = Ver men\u00fa -FileChooser.viewMenuButtonToolTipText = Ver men\u00fa -FileChooser.viewMenuLabel.textAndMnemonic = Ver -FileChooser.newFolderActionLabelText = Nueva Carpeta -FileChooser.listViewActionLabelText = Lista -FileChooser.detailsViewActionLabelText = Detalles -FileChooser.refreshActionLabelText = Refrescar -FileChooser.sortMenuLabelText = Ordenar \u00edconos por -FileChooser.viewMenuLabelText = Ver -FileChooser.fileSizeKiloBytes = {0} KB -FileChooser.fileSizeMegaBytes = {0} MB -FileChooser.fileSizeGigaBytes = {0} GB -FileChooser.folderNameLabelText = Nombre de carpeta: - -error.occured = Ocurri\u00f3 un error : %error% -button.abort = Abortar -button.retry = Reintentar -button.ignore = Ignorar - -font.source = Origen de la fuente: - -#after version 1.6.7: - -menu.export = Exportar -menu.general = General -menu.language = Lenguaje - -startup.welcometo = Bienvenido a -startup.selectopen = Clickee en el \u00edcono del panel superior o arrastre el archivo SWF a esta ventana para comenzar. - -error.font.nocharacter = Fuente de origen seleccionado no contiene caracteres "%char%". - -warning.initializers = Los campos est\u00e1ticos y constantes son a menudo inicializados en el inicializador.\nEditar el valor aqu\u00ed usualmente no es suficiente! - -#after version 1.7.0u1: - -menu.tools.searchMemory = Buscar SWFs en memoria -menu.file.reload = Recargar -message.confirm.reload = Esta acci\u00f3n eliminar\u00e1 todos lo cambios no guardados y recargar\u00e1 el archivo SWF otra vez.\nDesea continuar? - -dialog.selectbkcolor.title = Seleccionar color de fondo para la visualizaci\u00f3n del SWF -button.selectbkcolor.hint = Seleccionar color de fondo - -ColorChooser.okText = OK -ColorChooser.cancelText = Cancelar -ColorChooser.resetText = Reiniciar -ColorChooser.previewText = Vista previa -ColorChooser.swatchesNameText = Muestras -ColorChooser.swatchesRecentText = Reciente: -ColorChooser.sampleText = Texto de muestra Texto de muestra - -#after version 1.7.1: - -preview.play = Reproducir -preview.pause = Pausar -preview.stop = Detener - -message.confirm.removemultiple = Est\u00e1 seguro que desea eliminar %count% art\u00edculos\n y todos los objetos que dependen de el? - -menu.tools.searchCache = Buscar cache del navegador - -#after version 1.7.2u2 - -error.trait.exists = La caracter\u00edstica con nombre "%name%" ya existe. -button.addtrait = Agregar caracter\u00edstica -button.font.embed = Incrustar... -button.yes.all = Si a todo -button.no.all = No a todo -message.font.add.exists = El caracter %char% ya existe en la etiqueta de la fuente.\nDesea reemplazarlo? - -filter.gfx = Archivos ScaleForm GFx (*.gfx) -filter.supported = Todos los tipos de archivo soportados -work.canceled = Cancelado -work.restoringControlFlow = Restaurando control de flujo -menu.advancedsettings.advancedsettings = Opciones Avanzadas -menu.recentFiles = Archivos recientes - -#after version 1.7.4 -work.restoringControlFlow.complete = Control de Flujo restaurado -message.confirm.recentFileNotFound = Archivo no encontrado. Desea removerlo de la lista de archivos recientes? -contextmenu.closeSwf = Cerrar SWF -menu.settings.autoRenameIdentifiers = Auto renombrar identificadores -menu.file.saveasexe = Guardar como ejecutable... -filter.exe = Archivos ejecutables (*.exe) - -#after version 1.8.0 -font.updateTexts = Actualizar textos - -#after version 1.8.0u1 -menu.file.close = Cerrar -menu.file.closeAll = Cerrar todos -menu.tools.otherTools = Otros -menu.tools.otherTools.clearRecentFiles = Limpiar archivos recientes -fontName.name = Nombre de fuentes para mostrar: -fontName.copyright = Derechos de autor de la fuente: -button.preview = Vista previa -button.reset = Reiniciar -errors.info = Hay INFORMATIONS en el log. Clickear para ver. -errors.warning = Hay WARNINGS en el log. Clickear para ver. - -decompilationError = Error de decompilaci\u00f3n - -disassemblingProgress.toString = toString -disassemblingProgress.reading = Leyendo -disassemblingProgress.deobfuscating = Desofuscando - -contextmenu.moveTag = Mover etiqueta a - -filter.swc = Archivo de componente SWC (*.swc) -filter.zip = Archivo comprimido ZIP (*.zip) -filter.binary = B\u00fasqueda binaria - todos los archivos (*.*) - -open.error = Error -open.error.fileNotFound = Archivo no encontrado -open.error.cannotOpen = No se puede abrir el archivo - -node.others = otros - -#after version 1.8.1 -menu.tools.search = B\u00fasqueda de texto - -#after version 1.8.1u1 -menu.tools.timeline = L\u00ednea de tiempo - -dialog.selectcolor.title = Seleccionar color -button.selectcolor.hint = Click para seleccionar color - -#default item name, will be used in following sentences -generictag.array.item = item -generictag.array.insertbeginning = Insertar %item% al comienzo -generictag.array.insertbefore = Insertar %item% antes -generictag.array.remove = Remover %item% -generictag.array.insertafter = Insertar %item% despu\u00e9s -generictag.array.insertend = Insertar %item% al final - -#after version 2.0.0 -contextmenu.expandAll = Expandir todo -binaryData.truncateWarning = %count% bytes truncados. -filter.sounds = Formatos de sonido soportados (*.wav, *.mp3) -filter.sounds.wav = Formato de archivo Wave (*.wav) -filter.sounds.mp3 = Formato comprimido MP3 (*.mp3) - -error.sound.invalid = Sonido Invalido. - -button.prev = Previo -button.next = Siguiente - -#after version 2.1.0 -message.action.playerglobal.title = Libreria necesitada PlayerGlobal -message.action.playerglobal.needed = Para la edicion directa de ActionScript 3, necesita descargar la libreria llamada "PlayerGlobal.swc" desde la pagina principal de Adobe.\r\n%adobehomepage%\r\nPresione OK para ir a la pagina de descarga. -message.action.playerglobal.place = Descargue la libreria llamada PlayerGlobal(.swc), y coloquela en el directorio\r\n%libpath%\r\n Presione OK para continuar. - -message.confirm.experimental.function = Esta funci\u00f3n es EXPERIMENTAL. Significa que no debe de confiar en los resultados y el archivo SWF puede ser no fucnional luego de guardarlo. -message.confirm.donotshowagain = No mostrar otra vez menu.import = Importar - -menu.import = Importar -menu.file.import.text = Importar texto -import.select.directory = Seleccionar directorio para importar -error.text.import = Error durante la importaci\u00f3n del texto. \u00bfDesea continuar? - -#after version 2.1.1 -contextmenu.removeWithDependencies = Remover con dependencias - -abc.action.find-usages = Buscar usos -abc.action.find-declaration = Buscar declaraciones - -contextmenu.rawEdit = Edici\u00f3n cruda -contextmenu.jumpToCharacter = Ir a caracter - -menu.settings.dumpView = Volcar view - -menu.view = Ver -menu.file.view.resources = Recursos -menu.file.view.hex = Volcado Hex - -node.header = header - -header.signature = Firma: -header.compression = Compresi\u00f3n: -header.compression.lzma = LZMA -header.compression.zlib = ZLIB -header.compression.none = Sin compresi\u00f3n -header.version = Versi\u00f3n del SWF: -header.gfx = GFX: -header.filesize = Tama\u00f1o del archivo: -header.framerate = Velocidad de fotogramas: -header.framecount = Recuento de fotogramas: -header.displayrect = Mostrar rect: -header.displayrect.value.twips = %xmin%,%ymin% => %xmax%,%ymax% twips -header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% pixels - -#after version 2.1.2 -contextmenu.saveToFile = Guardar en un archivo -contextmenu.parseActions = Analizar actions -contextmenu.parseABC = Analizar ABC -contextmenu.parseInstructions = Analizar instrucciones AVM2 - -#after version 2.1.3 -menu.deobfuscation = Desofuscaci\u00f3n -menu.file.deobfuscation.old = Estilo viejo -menu.file.deobfuscation.new = Estilo nuevo - -#after version 2.1.4 -contextmenu.openswfinside = Abrir SWF inside -binarydata.swfInside = Parece que hay un SWF dentro de la etiqueta de datos binarios. Click aqu\u00ed para cargarlo como un sub-\u00e1rbol. - -#after version 3.0.0 -button.zoomin.hint = Acercar -button.zoomout.hint = Alejar -button.zoomfit.hint = Ampliar para adaptarse -button.zoomnone.hint = Ampliar hasta 1:1 -button.snapshot.hint = Tomar captura en el portapapeles - -editorTruncateWarning = Texto truncado en la posici\u00f3n %chars% en modo depuraci\u00f3n. - -#Font name which is presented in the SWF Font tag -font.name.intag = Nombre de fuente en etiqueta: - -menu.debugger = Depurador -menu.debugger.switch = Depurador -menu.debugger.replacetrace = Reemplazar llamadas de seguimiento -menu.debugger.showlog = Mostrar registro - -message.debugger = Este depurador de SWF solo puede ser utilizado para imprimir mensajes a la ventana de registro, la consola del navegador o mediante alertas. No est\u00e1 dise\u00f1ado para caracter\u00edsticas como step code, puntos de ruptura, etc. - -contextmenu.addTag = Agregar etiqueta - -deobfuscation.comment.tryenable = Consejo: Puede intentar activando "Desofuscaci\u00f3n Autom\u00e1tica" en Ajustes -deobfuscation.comment.failed = La desofuscaci\u00f3n est\u00e1 activada pero la decompilaci\u00f3n a\u00fan falla. Si el archivo NO est\u00e1 ofuscado, desactive "Desofuscaci\u00f3n autom\u00e1tica" para obtener mejores resultados. - -#after version 4.0.2 -preview.nextframe = Siguiente marco -preview.prevframe = Marco previo -preview.gotoframe = Ir a marco... - -preview.gotoframe.dialog.title = Ir a marco -preview.gotoframe.dialog.message = Ingresar n\u00famero de marco (%min% - %max%) -preview.gotoframe.dialog.frame.error = N\u00famero de marco inv\u00e1lido. Debe ser un n\u00famero entre %min% y %max%. - -error.text.invalid.continue = Texto inv\u00e1lido: %text% en l\u00ednea %line%. Desea continuar? - -#after version 4.0.5 -contextmenu.copyTag = Copiar etiqueta a -fit = encajar -button.setAdvanceValues = Establecer valores por anticipado - -menu.tools.replace = Reemplazo de texto - -message.confirm.close = Hay cambios sin guardar. De verdad quiere cerrar {swfName}? -message.confirm.closeAll = Hay cambios sin guardar. De verdad quiere cerrar todos los archivos SWFs? - -contextmenu.exportJavaSource = Exportar c\u00f3digo Java -contextmenu.exportSwfXml = Exportar SWF como XML -contextmenu.importSwfXml = Importar SWF XML - -filter.xml = XML - -#after version 4.1.0 -contextmenu.undo = Deshacer - -text.align.left = Alineaci\u00f3n izquierda -text.align.right = Alineaci\u00f3n derecha -text.align.center = Alineaci\u00f3n centrada -text.align.justify = Justificar alineaci\u00f3n - -text.undo = Deshacer cambios - -menu.file.import.xml = Importar SWF XML -menu.file.export.xml = Exportar SWF XML - -#after version 4.1.1 -text.align.translatex.decrease = Decrementar TranslateX -text.align.translatex.increase = Incrementar TranslateX -selectPreviousTag = Seleccionar etiqueta previa -selectNextTag = Seleccionar siguiente etiqueta -button.ignoreAll = Ignorar todo -menu.file.import.symbolClass = Clase Symbol -text.toggleCase = Conmutar may\u00fasculas y min\u00fasculas - -#after version 5.0.2 -preview.loop = Bucle -menu.file.import.script = Importar scripts -contextmenu.copyTagWithDependencies = Copiar etiqueta con dependencias a -button.replaceWithTag = Reemplazar con otro caracter de etiqueta -button.resolveConstants = Resolver constantes - -#after version 5.1.0 -button.viewConstants = Ver constantes -work.exported = Exportado -button.replaceAlphaChannel = Reemplazar canal alpha... - -tagInfo.header.name = Nombre -tagInfo.header.value = Valor -tagInfo.tagType = Tipo de etiqueta -tagInfo.characterId = Identificador de caracter -tagInfo.offset = Desplazamiento -tagInfo.length = Longitud -tagInfo.bounds = L\u00edmites -tagInfo.width = Anchura -tagInfo.height = Altura -tagInfo.neededCharacters = Caracteres necesarios - -button.viewhexpcode = Ver hexadecimal con instrucciones -taginfo.header = Informaci\u00f3n b\u00e1sica de etiqueta - -tagInfo.dependentCharacters = Caracteres dependientes - -#after version 5.3.0 -header.uncompressed = Descomprimido -header.warning.unsupportedGfxCompression = GFX soporta solo contenido descomprimido o comprimido con Zlib. -header.warning.minimumZlibVersion = Compresi\u00f3n con Zlib necesita versi\u00f3n 6 o mayor de SWF. -header.warning.minimumLzmaVersion = Compresi\u00f3n con LZMA necesita versi\u00f3n 13 o mayor de SWF. - -tagInfo.codecName = Nombre del Codec -tagInfo.exportFormat = Exportar formato -tagInfo.samplingRate = Tasa de muestreo -tagInfo.stereo = Est\u00e9reo -tagInfo.sampleCount = Recuento de muestra - -filter.dmg = Archivos ejecutables Mac (*.dmg) -filter.linuxExe = Archivos ejecutables Linux - -import.script.result = %count% fueron importados. -import.script.as12warning = Importar script solo puede importar scripts AS1/2. - -error.constantPoolTooBig = La Constant pool es demasiado grande. \u00edndice=%index%, tama\u00f1o=%size% -error.image.alpha.invalid = Datos de canal alpha no v\u00e1lidos - -#after version 6.0.2 -contextmenu.saveUncompressedToFile = Guardar en archivo no comprimido -abc.traitslist.scriptinitializer = inicializador de script -menu.settings.autoOpenLoadedSWFs = Abrir los SWFs cargados mientras se reproducen - -#after version 6.1.1 -menu.file.start = Comenzar -menu.file.start.run = Ejecutar -menu.file.start.stop = Detener -menu.file.start.debug = Depurar -menu.debugging = Depurando -menu.debugging.debug = Depurar -menu.debugging.debug.stop = Detener -menu.debugging.debug.pause = Pausar -menu.debugging.debug.stepOver = Pasar por encima -menu.debugging.debug.stepInto = Entrar en -menu.debugging.debug.stepOut = Pasar por encima -menu.debugging.debug.continue = Continuar -menu.debugging.debug.stack = Pila... -menu.debugging.debug.watch = Nueva vigilancia... - -message.playerpath.notset = Proyector de Flash Player no encontrado. Por favor, configure la ruta en Configuraciones Avanzadas / Rutas (1). -message.playerpath.debug.notset = Depurador de contenido Flash Player no encontrado. Por favor, configure la ruta en Configuraciones Avanzadas / Rutas (2). -message.playerpath.lib.notset = PlayerGlobal (.SWC) no encontrado. Por favor, configure su ruta en Configuraciones Avanzadas / Rutas (3). - -debugpanel.header = Depurando - -variables.header.registers = Registros -variables.header.locals = Locales -variables.header.arguments = Argumentos -variables.header.scopeChain = Cadena de alcance -variables.column.name = Nombre -variables.column.type = Tipo -variables.column.value = Valor - -callStack.header = Pila de llamadas -callStack.header.file = Archivo -callStack.header.line = L\u00ednea - -stack.header = Pila -stack.header.item = Item - -constantpool.header = Agrupaci\u00f3n de constantes -constantpool.header.id = Identificaci\u00f3n -constantpool.header.value = Valor - -work.running = Ejecutando -work.debugging = Depurando -work.debugging.instrumenting = Preparando SWF para depuraci\u00f3n -work.breakat = Detenerse a\u0020 -work.halted = Depuraci\u00f3n iniciada, ejecuci\u00f3n interrumpida. Agregue puntos de ruptura y haga click en Continuar (F5) para resumir la ejecuci\u00f3n. - -debuglog.header = Registro -debuglog.button.clear = Despejar - -#after 7.0.1 -work.debugging.wait = Esperando por la conecci\u00f3n del proyector de depuraci\u00f3n de Flash - -error.debug.listen = No se puede escuchar en el puerto %port%. Puede haber otro depurador de Flash ejecutandose. - -debug.break.reason.unknown = (Desconocido) -debug.break.reason.breakpoint = (Punto de ruptura) -debug.break.reason.watch = (Vigilante) -debug.break.reason.fault = (Falla) -debug.break.reason.stopRequest = (Detener pedido) -debug.break.reason.step = (Paso) -debug.break.reason.halt = (Interrumpir) -debug.break.reason.scriptLoaded = (Script cargado) - -menu.file.start.debugpcode = Depurar P-code - -#after 7.1.2 -button.replaceNoFill = Replace - L\u00edmites de actualizaci\u00f3n... -message.warning.svgImportExperimental = No todas las catacter\u00edsticas de SVG est\u00e1n soportadas. Solo el modo de llenado de color s\u00f3lido es soportado. Por favor, compruebe la anotaciones despu\u00e9s de importar. - -message.imported.swf = El archivo utiliza recursos de un archivo SWF importado: %url% Quiere que los recursos sean cargados desde dicha URL? -message.imported.swf.manually = No se puede cargar el SWF importado %url% El archivo o URL no existe. Desea seleccionar un archivo local? - -message.warning.hexViewNotUpToDate = Vista Hexadecimal no al d\u00eda. Por favor, guarde y recargue el archivo para actualizar Vista Hexadecimal. -message.font.replace.updateTexts = Algunos caracteres fueron reemplazados. Desea actualizar los textos existentes? - -menu.settings.simplifyExpressions = Simplificar expresiones - -#after 8.0.1 -menu.recentFiles.empty = La lista de archivos recientes est\u00e1 vac\u00eda -message.warning.outOfMemory32BitJre = Un error de Memoria insuficiente a sucedido. Usted est\u00e1 utilizando una versi\u00f3n de Java de 32 bit en un sistema de 64 bit. Por favor, utilice Java de 64 bit. - -menu.file.reloadAll = Recargar todo -message.confirm.reloadAll = Esta acci\u00f3n cancela todos los cambios no guardados en todos los archivos SWF y recarga toda la aplicaci\u00f3n nuevamente. Desea continuar? -export.script.singleFilePallelModeWarning = La exportaci\u00f3n de escritura de una sola fila no est\u00e1 soportada con la aceleraci\u00f3n permitida en paralelo +# Copyright (C) 2010-2016 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 . + +menu.file = Archivo +menu.file.open = Abrir... +menu.file.save = Guardar +menu.file.saveas = Guardar como... +menu.file.export.fla = Exportar a FLA +menu.file.export.all = Exportar todas las partes +menu.file.export.selection = Exportar selecci\u00f3n +menu.file.exit = Salir + +menu.tools = Herramientas +menu.tools.searchas = Buscar todo el ActionScript... +menu.tools.proxy = Proxy +menu.tools.deobfuscation = Desofuscaci\u00f3n +menu.tools.deobfuscation.pcode = Desofuscaci\u00f3n de PCode... +menu.tools.deobfuscation.globalrename = Renombrar identificador globalmente +menu.tools.deobfuscation.renameinvalid = Renombrar identificadores inv\u00e1lidos +menu.tools.gotoDocumentClass = Ir al document class + +menu.settings = Ajustes +menu.settings.autodeobfuscation = Desofuscaci\u00f3n autom\u00e1tica +menu.settings.internalflashviewer = Usar un visor de flash propio +menu.settings.parallelspeedup = Aceleraci\u00f3n en paralelo +menu.settings.disabledecompilation = Inhabilitar decompilaci\u00f3n (solo desensamblado) +menu.settings.addtocontextmenu = Agregar FFDec al men\u00fa contextual de archivos SWF +menu.settings.language = Cambiar lenguaje +menu.settings.cacheOnDisk = Usar almacenamiento de cach\u00e9 en disco +menu.settings.gotoMainClassOnStartup = Resaltar el document class al iniciar + +menu.help = Ayuda +menu.help.checkupdates = Comprobar actualizaciones... +menu.help.helpus = Ayudanos! +menu.help.homepage = Visitar la p\u00e1gina principal +menu.help.about = Acerca de... + +contextmenu.remove = Remover + +button.save = Guardar +button.edit = Editar +button.cancel = Cancelar +button.replace = Reemplazar... + +notavailonthisplatform = La vista previa de este objeto no est\u00e1 disponible en esta plataforma. (solo Windows) + +swfpreview = Vista previa del SWF +swfpreview.internal = Vista previa del SWF (Visor interno) + +parameters = Par\u00e1metros + +rename.enternew = Ingresar nuevo nombre: + +rename.finished.identifier = Identificador renombrado. +rename.finished.multiname = %count% multinombres(s) renombrado. + +node.texts = textos +node.images = im\u00e1genes +node.movies = pel\u00edculas +node.sounds = sonidos +node.binaryData = datosbinarios +node.fonts = fuentes +node.sprites = sprites +node.shapes = formas +node.morphshapes = morphshapes +node.buttons = botones +node.frames = marcos +node.scripts = scripts + +message.warning = Cuidado +message.confirm.experimental = El siguiente procedimiento puede da\u00f1ar el archivo SWF e inutilizar su reproducci\u00f3n.\r\nUSESE BAJO SU PROPIO RIESGO. Desea continuar? +message.confirm.parallel = El paralelismo puede acelerar la carga y la descompilaci\u00f3n pero requerir m\u00e1s memoria. +message.confirm.on = Desea encenderlo? +message.confirm.off = Desea apagarlo? +message.confirm = Confirmar + +message.confirm.autodeobfuscate = La desofuscaci\u00f3n autom\u00e1tica es una manera de descompilar el c\u00f3digo ofuscado.\r\nLa desofuscaci\u00f3n conduce a una descompilaci\u00f3n m\u00e1s lenta y a eliminar algo de c\u00f3digo muerto.\r\nSi el c\u00f3digo no est\u00e1 ofuscado, es mejor deshabilitar la autodesofuscaci\u00f3n. + +message.parallel = Paralelismo +message.trait.saved = Rasgo guardado existosamente + +message.constant.new.string = La cadena "%value%" no est\u00e1 presente en la tabla de constantes. Desea agregarla? +message.constant.new.string.title = Agregar cadena +message.constant.new.integer = El entero "%value%" no est\u00e1 presente en la tabla de constantes. Desea agregarlo? +message.constant.new.integer.title = Agregar entero +message.constant.new.unsignedinteger = El entero no signado "%value%" no est\u00e1 presente en la tabla de constantes. Desea agregarlo? +message.constant.new.unsignedinteger.title = Agregar entero no signado +message.constant.new.double = El entero doble "%value%" no est\u00e1 presente en la tabla de constantes. Desea agregarlo? +message.constant.new.double.title = Agregar entero doble + +work.buffering = Buffering +work.waitingfordissasembly = Esperando el desensamblado +work.gettinghilights = Adquiriendo resaltadores +work.disassembling = Desensamblando +work.exporting = Exportando +work.searching = Buscando +work.renaming = Renombrando +work.exporting.fla = Exportando FLA +work.renaming.identifiers = Renombrando identificadores +work.deobfuscating = Desofuscando +work.decompiling = Decompilando +work.gettingvariables = Adquiriendo variables +work.reading.swf = Leyendo SWF +work.creatingwindow = Creando ventana +work.buildingscripttree = Generando \u00e1rbol de script Building script tree + +work.deobfuscating.complete = Desofuscaci\u00f3n completada + +message.search.notfound = Cadena "%searchtext%" no encontrada. +message.search.notfound.title = No encontrado + +message.rename.notfound.multiname = No se encontr\u00f3 ning\u00fan multiname bajo el cursor +message.rename.notfound.identifier = No se encontr\u00f3 ning\u00fan identificador bajo el cursor +message.rename.notfound.title = No encontrado +message.rename.renamed = Identificadores renombrados: %count% + +filter.images = Im\u00e1genes (%extensions%) +filter.fla = Documento %version% (*.fla) +filter.xfl = Documento no comprimido %version% (*.xfl) +filter.swf = Archivos SWF (*.swf) + +error = Error +error.image.invalid = Im\u00e1gen inv\u00e1lida. + +error.text.invalid = Texto inv\u00e1lido: %text% en la l\u00ednea %line% +error.file.save = No se puede guardar el archivo +error.file.write = No se puede escribir al archivo +error.export = Error durante la exportaci\u00f3n + +export.select.directory = Seleccione directorio para exportar +export.finishedin = Exportado en %time% + +update.check.title = Chequeo de actualizaci\u00f3n +update.check.nonewversion = No hay versi\u00f3n nueva disponible. + +message.helpus = Por favor, visite\r\n%url%\r\npara m\u00e1s detalles. +message.homepage = Visite la p\u00e1gina principal en: \r\n%url% + +proxy = Proxy +proxy.start = Comenzar proxy +proxy.stop = Detener proxy +proxy.show = Mostrar proxy +exit = Salir + +panel.disassembled = Fuente P-code +panel.decompiled = Fuente ActionScript + +search.info = Buscar por "%text%" : +search.script = Script + +constants = Constantes +traits = Rasgos + +pleasewait = Espere por favor + +abc.detail.methodtrait = M\u00e9todo/Getter/Setter Rasgo +abc.detail.unsupported = - +abc.detail.slotconsttrait = Slot/Const Rasgo +abc.detail.traitname = Nombre: + +abc.detail.body.params.maxstack = Pila m\u00e1xima: +abc.detail.body.params.localregcount = Contador de registros locales: +abc.detail.body.params.minscope = Profundidad de alcance m\u00ednima: +abc.detail.body.params.maxscope = Profundidad de alcance m\u00e1xima: +abc.detail.body.params.autofill = Auto rellenado al salvar c\u00f3dig (AJUSTE GLOBAL) +abc.detail.body.params.autofill.experimental = ...EXPERIMENTAL + +abc.detail.methodinfo.methodindex = Indice de m\u00e9todo: +abc.detail.methodinfo.parameters = Par\u00e1metros: +abc.detail.methodinfo.returnvalue = Tipo de valor de retorno: + +error.methodinfo.params = Error de pa\u0155ametro MethodInfo +error.methodinfo.returnvalue = Error de retorno de tipo MethodInfo + +abc.detail.methodinfo = MethodInfo +abc.detail.body.code = C\u00f3digo de MethodBody +abc.detail.body.params = Par\u00e1metros de MethodBody + +abc.detail.slotconst.typevalue = Tipo y valor: + +error.slotconst.typevalue = Error de valor de tipo SlotConst + +message.autofill.failed = No se puede obtener las estad\u00edsticas de c\u00f3digo para los par\u00e1metros de cuerpo autom\u00e1ticos.\r\nDestilde auto-llenado para evitar este mensaje. +info.selecttrait = Seleccione la clase y clickee un atributo en el c\u00f3digo Actionscript para editarlo. + +button.viewgraph = Ver grafo +button.viewhex = Ver en hexa + +abc.traitslist.instanceinitializer = inicializador de instancia +abc.traitslist.classinitializer = inicializador de clase + +action.edit.experimental = (Experimental) + +message.action.saved = C\u00f3digo guardado exitosamente + +error.action.save = %error% en la l\u00ednea %line% + +message.confirm.remove = Est\u00e1 seguro que desea remover %item% \n y todos los objetos que dependen de \u00e9l? + +#after version 1.6.5u1: + +button.ok = OK +button.cancel = Cancelar + +font.name = Nombre de fuente: +font.isbold = Es negrita: +font.isitalic = Es it\u00e1lica: +font.ascent = Ascendente: +font.descent = Descendente: +font.leading = Destacado: +font.characters = Caract\u00e9r: +font.characters.add = Agregar caracteres: +value.unknown = ? + +yes = si +no = no + +errors.present = Hay ERRORES en el log. Clickear para ver. +errors.none = No hay errores en el log + +#after version 1.6.6: + +dialog.message.title = Mensaje +dialog.select.title = Seleccione una opci\u00f3n + +button.yes = Si +button.no = No + +FileChooser.openButtonText = Abrir +FileChooser.openButtonToolTipText = Abrir +FileChooser.lookInLabelText = Mirar en: +FileChooser.acceptAllFileFilterText = Todos los archivos +FileChooser.filesOfTypeLabelText = Archivos de tipo: +FileChooser.fileNameLabelText = Nombre de archivo: +FileChooser.listViewButtonToolTipText = Lista +FileChooser.listViewButtonAccessibleName = Lista +FileChooser.detailsViewButtonToolTipText = Detales +FileChooser.detailsViewButtonAccessibleName = Detalles +FileChooser.upFolderToolTipText = Subir un nivel +FileChooser.upFolderAccessibleName = Subir un nivel +FileChooser.homeFolderToolTipText = Home +FileChooser.homeFolderAccessibleName = Home +FileChooser.fileNameHeaderText = Nombre +FileChooser.fileSizeHeaderText = Tama\u00f1o +FileChooser.fileTypeHeaderText = Tipo +FileChooser.fileDateHeaderText = Fecha +FileChooser.fileAttrHeaderText = Atributos +FileChooser.openDialogTitleText = Abrir +FileChooser.directoryDescriptionText = Directorio +FileChooser.directoryOpenButtonText = Abrir +FileChooser.directoryOpenButtonToolTipText = Abrir el directorio seleccionado +FileChooser.fileDescriptionText = Archivo gen\u00e9rico +FileChooser.helpButtonText = Ayuda +FileChooser.helpButtonToolTipText = Ayuda de FileChooser +FileChooser.newFolderAccessibleName = Nueva carpeta +FileChooser.newFolderErrorText = Error creando nueva carpeta +FileChooser.newFolderToolTipText = Crear nueva carpeta +FileChooser.other.newFolder = NuevaCarpeta +FileChooser.other.newFolder.subsequent = NuevaCarpeta.{0} +FileChooser.win32.newFolder = Nueva Carpeta +FileChooser.win32.newFolder.subsequent = Nueva Carpeta ({0}) +FileChooser.saveButtonText = Guarda +FileChooser.saveButtonToolTipText = Guardar archivo seleccionado +FileChooser.saveDialogTitleText = Guardar +FileChooser.saveInLabelText = Guardar en: +FileChooser.updateButtonText = Actualizar +FileChooser.updateButtonToolTipText = Actualizar listado de directorio + +#after version 1.6.6u2: + +FileChooser.detailsViewActionLabel.textAndMnemonic = Detalles +FileChooser.detailsViewButtonToolTip.textAndMnemonic = Detalles +FileChooser.fileAttrHeader.textAndMnemonic = Atributos +FileChooser.fileDateHeader.textAndMnemonic = Modificado +FileChooser.fileNameHeader.textAndMnemonic = Nombre +FileChooser.fileNameLabel.textAndMnemonic = Nombre de archivo: +FileChooser.fileSizeHeader.textAndMnemonic = Tama\u00f1o +FileChooser.fileTypeHeader.textAndMnemonic = Tipo +FileChooser.filesOfTypeLabel.textAndMnemonic = Archivos de tipo: +FileChooser.folderNameLabel.textAndMnemonic = Nombre de carpeta: +FileChooser.homeFolderToolTip.textAndMnemonic = Home +FileChooser.listViewActionLabel.textAndMnemonic = Lista +FileChooser.listViewButtonToolTip.textAndMnemonic = Lista +FileChooser.lookInLabel.textAndMnemonic = Mirar en: +FileChooser.newFolderActionLabel.textAndMnemonic = Nueva Carpeta +FileChooser.newFolderToolTip.textAndMnemonic = Crear Nueva Carpeta +FileChooser.refreshActionLabel.textAndMnemonic = Refrescar +FileChooser.saveInLabel.textAndMnemonic = Guardar en: +FileChooser.upFolderToolTip.textAndMnemonic = Subir un nivel +FileChooser.viewMenuButtonAccessibleName = Ver men\u00fa +FileChooser.viewMenuButtonToolTipText = Ver men\u00fa +FileChooser.viewMenuLabel.textAndMnemonic = Ver +FileChooser.newFolderActionLabelText = Nueva Carpeta +FileChooser.listViewActionLabelText = Lista +FileChooser.detailsViewActionLabelText = Detalles +FileChooser.refreshActionLabelText = Refrescar +FileChooser.sortMenuLabelText = Ordenar \u00edconos por +FileChooser.viewMenuLabelText = Ver +FileChooser.fileSizeKiloBytes = {0} KB +FileChooser.fileSizeMegaBytes = {0} MB +FileChooser.fileSizeGigaBytes = {0} GB +FileChooser.folderNameLabelText = Nombre de carpeta: + +error.occured = Ocurri\u00f3 un error : %error% +button.abort = Abortar +button.retry = Reintentar +button.ignore = Ignorar + +font.source = Origen de la fuente: + +#after version 1.6.7: + +menu.export = Exportar +menu.general = General +menu.language = Lenguaje + +startup.welcometo = Bienvenido a +startup.selectopen = Clickee en el \u00edcono del panel superior o arrastre el archivo SWF a esta ventana para comenzar. + +error.font.nocharacter = Fuente de origen seleccionado no contiene caracteres "%char%". + +warning.initializers = Los campos est\u00e1ticos y constantes son a menudo inicializados en el inicializador.\nEditar el valor aqu\u00ed usualmente no es suficiente! + +#after version 1.7.0u1: + +menu.tools.searchMemory = Buscar SWFs en memoria +menu.file.reload = Recargar +message.confirm.reload = Esta acci\u00f3n eliminar\u00e1 todos lo cambios no guardados y recargar\u00e1 el archivo SWF otra vez.\nDesea continuar? + +dialog.selectbkcolor.title = Seleccionar color de fondo para la visualizaci\u00f3n del SWF +button.selectbkcolor.hint = Seleccionar color de fondo + +ColorChooser.okText = OK +ColorChooser.cancelText = Cancelar +ColorChooser.resetText = Reiniciar +ColorChooser.previewText = Vista previa +ColorChooser.swatchesNameText = Muestras +ColorChooser.swatchesRecentText = Reciente: +ColorChooser.sampleText = Texto de muestra Texto de muestra + +#after version 1.7.1: + +preview.play = Reproducir +preview.pause = Pausar +preview.stop = Detener + +message.confirm.removemultiple = Est\u00e1 seguro que desea eliminar %count% art\u00edculos\n y todos los objetos que dependen de el? + +menu.tools.searchCache = Buscar cache del navegador + +#after version 1.7.2u2 + +error.trait.exists = La caracter\u00edstica con nombre "%name%" ya existe. +button.addtrait = Agregar caracter\u00edstica +button.font.embed = Incrustar... +button.yes.all = Si a todo +button.no.all = No a todo +message.font.add.exists = El caracter %char% ya existe en la etiqueta de la fuente.\nDesea reemplazarlo? + +filter.gfx = Archivos ScaleForm GFx (*.gfx) +filter.supported = Todos los tipos de archivo soportados +work.canceled = Cancelado +work.restoringControlFlow = Restaurando control de flujo +menu.advancedsettings.advancedsettings = Opciones Avanzadas +menu.recentFiles = Archivos recientes + +#after version 1.7.4 +work.restoringControlFlow.complete = Control de Flujo restaurado +message.confirm.recentFileNotFound = Archivo no encontrado. Desea removerlo de la lista de archivos recientes? +contextmenu.closeSwf = Cerrar SWF +menu.settings.autoRenameIdentifiers = Auto renombrar identificadores +menu.file.saveasexe = Guardar como ejecutable... +filter.exe = Archivos ejecutables (*.exe) + +#after version 1.8.0 +font.updateTexts = Actualizar textos + +#after version 1.8.0u1 +menu.file.close = Cerrar +menu.file.closeAll = Cerrar todos +menu.tools.otherTools = Otros +menu.tools.otherTools.clearRecentFiles = Limpiar archivos recientes +fontName.name = Nombre de fuentes para mostrar: +fontName.copyright = Derechos de autor de la fuente: +button.preview = Vista previa +button.reset = Reiniciar +errors.info = Hay INFORMATIONS en el log. Clickear para ver. +errors.warning = Hay WARNINGS en el log. Clickear para ver. + +decompilationError = Error de decompilaci\u00f3n + +disassemblingProgress.toString = toString +disassemblingProgress.reading = Leyendo +disassemblingProgress.deobfuscating = Desofuscando + +contextmenu.moveTag = Mover etiqueta a + +filter.swc = Archivo de componente SWC (*.swc) +filter.zip = Archivo comprimido ZIP (*.zip) +filter.binary = B\u00fasqueda binaria - todos los archivos (*.*) + +open.error = Error +open.error.fileNotFound = Archivo no encontrado +open.error.cannotOpen = No se puede abrir el archivo + +node.others = otros + +#after version 1.8.1 +menu.tools.search = B\u00fasqueda de texto + +#after version 1.8.1u1 +menu.tools.timeline = L\u00ednea de tiempo + +dialog.selectcolor.title = Seleccionar color +button.selectcolor.hint = Click para seleccionar color + +#default item name, will be used in following sentences +generictag.array.item = item +generictag.array.insertbeginning = Insertar %item% al comienzo +generictag.array.insertbefore = Insertar %item% antes +generictag.array.remove = Remover %item% +generictag.array.insertafter = Insertar %item% despu\u00e9s +generictag.array.insertend = Insertar %item% al final + +#after version 2.0.0 +contextmenu.expandAll = Expandir todo +binaryData.truncateWarning = %count% bytes truncados. +filter.sounds = Formatos de sonido soportados (*.wav, *.mp3) +filter.sounds.wav = Formato de archivo Wave (*.wav) +filter.sounds.mp3 = Formato comprimido MP3 (*.mp3) + +error.sound.invalid = Sonido Invalido. + +button.prev = Previo +button.next = Siguiente + +#after version 2.1.0 +message.action.playerglobal.title = Libreria necesitada PlayerGlobal +message.action.playerglobal.needed = Para la edicion directa de ActionScript 3, necesita descargar la libreria llamada "PlayerGlobal.swc" desde la pagina principal de Adobe.\r\n%adobehomepage%\r\nPresione OK para ir a la pagina de descarga. +message.action.playerglobal.place = Descargue la libreria llamada PlayerGlobal(.swc), y coloquela en el directorio\r\n%libpath%\r\n Presione OK para continuar. + +message.confirm.experimental.function = Esta funci\u00f3n es EXPERIMENTAL. Significa que no debe de confiar en los resultados y el archivo SWF puede ser no fucnional luego de guardarlo. +message.confirm.donotshowagain = No mostrar otra vez menu.import = Importar + +menu.import = Importar +menu.file.import.text = Importar texto +import.select.directory = Seleccionar directorio para importar +error.text.import = Error durante la importaci\u00f3n del texto. \u00bfDesea continuar? + +#after version 2.1.1 +contextmenu.removeWithDependencies = Remover con dependencias + +abc.action.find-usages = Buscar usos +abc.action.find-declaration = Buscar declaraciones + +contextmenu.rawEdit = Edici\u00f3n cruda +contextmenu.jumpToCharacter = Ir a caracter + +menu.settings.dumpView = Volcar view + +menu.view = Ver +menu.file.view.resources = Recursos +menu.file.view.hex = Volcado Hex + +node.header = header + +header.signature = Firma: +header.compression = Compresi\u00f3n: +header.compression.lzma = LZMA +header.compression.zlib = ZLIB +header.compression.none = Sin compresi\u00f3n +header.version = Versi\u00f3n del SWF: +header.gfx = GFX: +header.filesize = Tama\u00f1o del archivo: +header.framerate = Velocidad de fotogramas: +header.framecount = Recuento de fotogramas: +header.displayrect = Mostrar rect: +header.displayrect.value.twips = %xmin%,%ymin% => %xmax%,%ymax% twips +header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% pixels + +#after version 2.1.2 +contextmenu.saveToFile = Guardar en un archivo +contextmenu.parseActions = Analizar actions +contextmenu.parseABC = Analizar ABC +contextmenu.parseInstructions = Analizar instrucciones AVM2 + +#after version 2.1.3 +menu.deobfuscation = Desofuscaci\u00f3n +menu.file.deobfuscation.old = Estilo viejo +menu.file.deobfuscation.new = Estilo nuevo + +#after version 2.1.4 +contextmenu.openswfinside = Abrir SWF inside +binarydata.swfInside = Parece que hay un SWF dentro de la etiqueta de datos binarios. Click aqu\u00ed para cargarlo como un sub-\u00e1rbol. + +#after version 3.0.0 +button.zoomin.hint = Acercar +button.zoomout.hint = Alejar +button.zoomfit.hint = Ampliar para adaptarse +button.zoomnone.hint = Ampliar hasta 1:1 +button.snapshot.hint = Tomar captura en el portapapeles + +editorTruncateWarning = Texto truncado en la posici\u00f3n %chars% en modo depuraci\u00f3n. + +#Font name which is presented in the SWF Font tag +font.name.intag = Nombre de fuente en etiqueta: + +menu.debugger = Depurador +menu.debugger.switch = Depurador +menu.debugger.replacetrace = Reemplazar llamadas de seguimiento +menu.debugger.showlog = Mostrar registro + +message.debugger = Este depurador de SWF solo puede ser utilizado para imprimir mensajes a la ventana de registro, la consola del navegador o mediante alertas. No est\u00e1 dise\u00f1ado para caracter\u00edsticas como step code, puntos de ruptura, etc. + +contextmenu.addTag = Agregar etiqueta + +deobfuscation.comment.tryenable = Consejo: Puede intentar activando "Desofuscaci\u00f3n Autom\u00e1tica" en Ajustes +deobfuscation.comment.failed = La desofuscaci\u00f3n est\u00e1 activada pero la decompilaci\u00f3n a\u00fan falla. Si el archivo NO est\u00e1 ofuscado, desactive "Desofuscaci\u00f3n autom\u00e1tica" para obtener mejores resultados. + +#after version 4.0.2 +preview.nextframe = Siguiente marco +preview.prevframe = Marco previo +preview.gotoframe = Ir a marco... + +preview.gotoframe.dialog.title = Ir a marco +preview.gotoframe.dialog.message = Ingresar n\u00famero de marco (%min% - %max%) +preview.gotoframe.dialog.frame.error = N\u00famero de marco inv\u00e1lido. Debe ser un n\u00famero entre %min% y %max%. + +error.text.invalid.continue = Texto inv\u00e1lido: %text% en l\u00ednea %line%. Desea continuar? + +#after version 4.0.5 +contextmenu.copyTag = Copiar etiqueta a +fit = encajar +button.setAdvanceValues = Establecer valores por anticipado + +menu.tools.replace = Reemplazo de texto + +message.confirm.close = Hay cambios sin guardar. De verdad quiere cerrar {swfName}? +message.confirm.closeAll = Hay cambios sin guardar. De verdad quiere cerrar todos los archivos SWFs? + +contextmenu.exportJavaSource = Exportar c\u00f3digo Java +contextmenu.exportSwfXml = Exportar SWF como XML +contextmenu.importSwfXml = Importar SWF XML + +filter.xml = XML + +#after version 4.1.0 +contextmenu.undo = Deshacer + +text.align.left = Alineaci\u00f3n izquierda +text.align.right = Alineaci\u00f3n derecha +text.align.center = Alineaci\u00f3n centrada +text.align.justify = Justificar alineaci\u00f3n + +text.undo = Deshacer cambios + +menu.file.import.xml = Importar SWF XML +menu.file.export.xml = Exportar SWF XML + +#after version 4.1.1 +text.align.translatex.decrease = Decrementar TranslateX +text.align.translatex.increase = Incrementar TranslateX +selectPreviousTag = Seleccionar etiqueta previa +selectNextTag = Seleccionar siguiente etiqueta +button.ignoreAll = Ignorar todo +menu.file.import.symbolClass = Clase Symbol +text.toggleCase = Conmutar may\u00fasculas y min\u00fasculas + +#after version 5.0.2 +preview.loop = Bucle +menu.file.import.script = Importar scripts +contextmenu.copyTagWithDependencies = Copiar etiqueta con dependencias a +button.replaceWithTag = Reemplazar con otro caracter de etiqueta +button.resolveConstants = Resolver constantes + +#after version 5.1.0 +button.viewConstants = Ver constantes +work.exported = Exportado +button.replaceAlphaChannel = Reemplazar canal alpha... + +tagInfo.header.name = Nombre +tagInfo.header.value = Valor +tagInfo.tagType = Tipo de etiqueta +tagInfo.characterId = Identificador de caracter +tagInfo.offset = Desplazamiento +tagInfo.length = Longitud +tagInfo.bounds = L\u00edmites +tagInfo.width = Anchura +tagInfo.height = Altura +tagInfo.neededCharacters = Caracteres necesarios + +button.viewhexpcode = Ver hexadecimal con instrucciones +taginfo.header = Informaci\u00f3n b\u00e1sica de etiqueta + +tagInfo.dependentCharacters = Caracteres dependientes + +#after version 5.3.0 +header.uncompressed = Descomprimido +header.warning.unsupportedGfxCompression = GFX soporta solo contenido descomprimido o comprimido con Zlib. +header.warning.minimumZlibVersion = Compresi\u00f3n con Zlib necesita versi\u00f3n 6 o mayor de SWF. +header.warning.minimumLzmaVersion = Compresi\u00f3n con LZMA necesita versi\u00f3n 13 o mayor de SWF. + +tagInfo.codecName = Nombre del Codec +tagInfo.exportFormat = Exportar formato +tagInfo.samplingRate = Tasa de muestreo +tagInfo.stereo = Est\u00e9reo +tagInfo.sampleCount = Recuento de muestra + +filter.dmg = Archivos ejecutables Mac (*.dmg) +filter.linuxExe = Archivos ejecutables Linux + +import.script.result = %count% fueron importados. +import.script.as12warning = Importar script solo puede importar scripts AS1/2. + +error.constantPoolTooBig = La Constant pool es demasiado grande. \u00edndice=%index%, tama\u00f1o=%size% +error.image.alpha.invalid = Datos de canal alpha no v\u00e1lidos + +#after version 6.0.2 +contextmenu.saveUncompressedToFile = Guardar en archivo no comprimido +abc.traitslist.scriptinitializer = inicializador de script +menu.settings.autoOpenLoadedSWFs = Abrir los SWFs cargados mientras se reproducen + +#after version 6.1.1 +menu.file.start = Comenzar +menu.file.start.run = Ejecutar +menu.file.start.stop = Detener +menu.file.start.debug = Depurar +menu.debugging = Depurando +menu.debugging.debug = Depurar +menu.debugging.debug.stop = Detener +menu.debugging.debug.pause = Pausar +menu.debugging.debug.stepOver = Pasar por encima +menu.debugging.debug.stepInto = Entrar en +menu.debugging.debug.stepOut = Pasar por encima +menu.debugging.debug.continue = Continuar +menu.debugging.debug.stack = Pila... +menu.debugging.debug.watch = Nueva vigilancia... + +message.playerpath.notset = Proyector de Flash Player no encontrado. Por favor, configure la ruta en Configuraciones Avanzadas / Rutas (1). +message.playerpath.debug.notset = Depurador de contenido Flash Player no encontrado. Por favor, configure la ruta en Configuraciones Avanzadas / Rutas (2). +message.playerpath.lib.notset = PlayerGlobal (.SWC) no encontrado. Por favor, configure su ruta en Configuraciones Avanzadas / Rutas (3). + +debugpanel.header = Depurando + +variables.header.registers = Registros +variables.header.locals = Locales +variables.header.arguments = Argumentos +variables.header.scopeChain = Cadena de alcance +variables.column.name = Nombre +variables.column.type = Tipo +variables.column.value = Valor + +callStack.header = Pila de llamadas +callStack.header.file = Archivo +callStack.header.line = L\u00ednea + +stack.header = Pila +stack.header.item = Item + +constantpool.header = Agrupaci\u00f3n de constantes +constantpool.header.id = Identificaci\u00f3n +constantpool.header.value = Valor + +work.running = Ejecutando +work.debugging = Depurando +work.debugging.instrumenting = Preparando SWF para depuraci\u00f3n +work.breakat = Detenerse a\u0020 +work.halted = Depuraci\u00f3n iniciada, ejecuci\u00f3n interrumpida. Agregue puntos de ruptura y haga click en Continuar (F5) para resumir la ejecuci\u00f3n. + +debuglog.header = Registro +debuglog.button.clear = Despejar + +#after 7.0.1 +work.debugging.wait = Esperando por la conecci\u00f3n del proyector de depuraci\u00f3n de Flash + +error.debug.listen = No se puede escuchar en el puerto %port%. Puede haber otro depurador de Flash ejecutandose. + +debug.break.reason.unknown = (Desconocido) +debug.break.reason.breakpoint = (Punto de ruptura) +debug.break.reason.watch = (Vigilante) +debug.break.reason.fault = (Falla) +debug.break.reason.stopRequest = (Detener pedido) +debug.break.reason.step = (Paso) +debug.break.reason.halt = (Interrumpir) +debug.break.reason.scriptLoaded = (Script cargado) + +menu.file.start.debugpcode = Depurar P-code + +#after 7.1.2 +button.replaceNoFill = Replace - L\u00edmites de actualizaci\u00f3n... +message.warning.svgImportExperimental = No todas las catacter\u00edsticas de SVG est\u00e1n soportadas. Solo el modo de llenado de color s\u00f3lido es soportado. Por favor, compruebe la anotaciones despu\u00e9s de importar. + +message.imported.swf = El archivo utiliza recursos de un archivo SWF importado: %url% Quiere que los recursos sean cargados desde dicha URL? +message.imported.swf.manually = No se puede cargar el SWF importado %url% El archivo o URL no existe. Desea seleccionar un archivo local? + +message.warning.hexViewNotUpToDate = Vista Hexadecimal no al d\u00eda. Por favor, guarde y recargue el archivo para actualizar Vista Hexadecimal. +message.font.replace.updateTexts = Algunos caracteres fueron reemplazados. Desea actualizar los textos existentes? + +menu.settings.simplifyExpressions = Simplificar expresiones + +#after 8.0.1 +menu.recentFiles.empty = La lista de archivos recientes est\u00e1 vac\u00eda +message.warning.outOfMemory32BitJre = Un error de Memoria insuficiente a sucedido. Usted est\u00e1 utilizando una versi\u00f3n de Java de 32 bit en un sistema de 64 bit. Por favor, utilice Java de 64 bit. + +menu.file.reloadAll = Recargar todo +message.confirm.reloadAll = Esta acci\u00f3n cancela todos los cambios no guardados en todos los archivos SWF y recarga toda la aplicaci\u00f3n nuevamente. Desea continuar? +export.script.singleFilePallelModeWarning = La exportaci\u00f3n de escritura de una sola fila no est\u00e1 soportada con la aceleraci\u00f3n permitida en paralelo + +button.showOriginalBytesInPcodeHex = Mostrar bytes originales diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_it.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_it.properties index dbfe30570..35c4f5fcc 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_it.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_it.properties @@ -1,715 +1,715 @@ -# Copyright (C) 2010-2016 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 . - -menu.file = File -menu.file.open = Apri... -menu.file.save = Salva -menu.file.saveas = Salva come... -menu.file.export.fla = Esporta come FLA -menu.file.export.all = Esporta tutte le parti -menu.file.export.selection = Esporta selezione -menu.file.exit = Esci - -menu.tools = Strumenti -menu.tools.searchas = Cerca in tutti gli ActionScript... -menu.tools.proxy = Proxy -menu.tools.deobfuscation = Deoffuscamento -menu.tools.deobfuscation.pcode = Deoffuscamento P-code... -menu.tools.deobfuscation.globalrename = Rinomina identificatore globalmente -menu.tools.deobfuscation.renameinvalid = Rinomina identificatori non validi -menu.tools.gotoDocumentClass = Vai a document class - -menu.settings = Impostazioni -menu.settings.autodeobfuscation = Deoffuscamento automatico -menu.settings.internalflashviewer = Usa visualizzatore Flash incorporato -menu.settings.parallelspeedup = Accelerazione parallela -menu.settings.disabledecompilation = Disattiva la decompilazione (solo disassembly) -menu.settings.addtocontextmenu = Mostra FFDec nel menu contestuale per file SWF -menu.settings.language = Cambia la lingua -menu.settings.cacheOnDisk = Utilizza la cache su disco -menu.settings.gotoMainClassOnStartup = Evidenzia la document class all'avvio - -menu.help = Aiuto -menu.help.checkupdates = Controllo aggiornamenti... -menu.help.helpus = Dateci una mano! -menu.help.homepage = Visita il sito web -menu.help.about = Informazioni su... - -contextmenu.remove = Rimuovi - -button.save = Salva -button.edit = Modifica -button.cancel = Annulla -button.replace = Sostituisci... - -notavailonthisplatform = L'anteprima di questo oggetto \u00e8 disponibile solo su sistema operativo Windows. - -swfpreview = Anteprima SWF -swfpreview.internal = Anteprima SWF (visualizzatore incorporato) - -parameters = Parametri - -rename.enternew = Nuovo nome: - -rename.finished.identifier = Identificatore rinominato con successo. -rename.finished.multiname = %count% multiname rinominati. - -node.texts = text -node.images = image -node.movies = movie -node.sounds = sound -node.binaryData = BinaryData -node.fonts = font -node.sprites = sprite -node.shapes = shape -node.morphshapes = morphshape -node.buttons = button -node.frames = frame -node.scripts = script - -message.warning = Avvertenza -message.confirm.experimental = Questa procedura pu\u00f2 danneggiare il file SWF e renderlo irriproducibile.\r\nUSARE\u00a0A\u00a0PROPRIO\u00a0RISCHIO. Si desidera abilitare comunque? -message.confirm.parallel = L'esecuzione parallela velocizza il caricamento e la decompilazione ma usa pi\u00f9 memoria. -message.confirm.on = ABILITARE\u00a0questa opzione? -message.confirm.off = DISABILITARE\u00a0questa opzione? -message.confirm = Conferma - -message.confirm.autodeobfuscate = Il deoffuscamento automatico permette di decompilare codice offuscato.\r\nQuesto rallenta la decompilazione e pu\u00f2 comportare l'eliminazione di codice morto.\r\nSe il codice non \u00e8 offuscato, \u00e8 preferibile disattivare il deoffuscamento. - -message.parallel = Parallelismo -message.trait.saved = Trait salvato con successo - -message.constant.new.string = Stringa di caratteri "%value%" non presente nella tabella delle costanti. Aggiungere? -message.constant.new.string.title = Aggiunto String -message.constant.new.integer = Valore intero "%value%" not presente nella tabella delle costanti. Aggiungere? -message.constant.new.integer.title = Aggiunto Integer -message.constant.new.unsignedinteger = Valore intero senza segno "%value%" not presente nella tabella delle costanti. Aggiungere? -message.constant.new.unsignedinteger.title = Aggiunto Integer senza segno -message.constant.new.double = Valore a doppia precisione "%value%" not presente nella tabella delle costanti. Aggiungere? -message.constant.new.double.title = Aggiunto Double - -work.buffering = Buffering in corso -work.waitingfordissasembly = In attesa del disassembly -work.gettinghilights = Recupero degli highlight -work.disassembling = Disassembly in corso -work.exporting = Esportazione in corso -work.searching = Ricerca in corso -work.renaming = Rinomina in corso -work.exporting.fla = Esportazione FLA -work.renaming.identifiers = Rinomina identificatori -work.deobfuscating = Deoffuscamento -work.decompiling = Decompilazione in corso -work.gettingvariables = Lettura variabili -work.reading.swf = Lettura SWF -work.creatingwindow = Creazione finestra -work.buildingscripttree = Creazione gerarchia degli script - -work.deobfuscating.complete = Deoffuscamento completato - -message.search.notfound = Stringa "%searchtext%" non trovata. -message.search.notfound.title = Non trovato - -message.rename.notfound.multiname = Nessun multiname alla posizione corrente -message.rename.notfound.identifier = Nessun identificatore alla posizione corrente -message.rename.notfound.title = Non trovato -message.rename.renamed = %count% identificatori renominati. - -filter.images = Immagini (%extensions%) -filter.fla = Documento %version% (*.fla) -filter.xfl = Documento non compresso %version%(*.xfl) -filter.swf = File SWF (*.swf) - -error = Errore -error.image.invalid = Immagine non valida. - -error.text.invalid = Testo non valido alla riga %line%: %text% -error.file.save = Impossibile salvare il file -error.file.write = Impossibile scrivere su file -error.export = Errore durante l'esportazione - -export.select.directory = Selezionare la cartella di esportazione -export.finishedin = Esportato in %time% - -update.check.title = Controllo aggiornamenti -update.check.nonewversion = Nessuna nuova versione disponibile. - -message.helpus = Per maggiori dettagli si prega di visitare\r\n%url%\r\n -message.homepage = Visita la homepage:\r\n%url% - -proxy = Proxy -proxy.start = Avvio proxy -proxy.stop = Arresta proxy -proxy.show = Mostra proxy -exit = Esci - -panel.disassembled = Sorgente P-code -panel.decompiled = Sorgente ActionScript - -search.info = Cerca "%text%": -search.script = Script - -constants = Costanti -traits = Trait - -pleasewait = Attendere prego - -abc.detail.methodtrait = Trait di Metodo/Getter/Setter -abc.detail.unsupported = - -abc.detail.slotconsttrait = Trait Slot/Const -abc.detail.traitname = Nome: - -abc.detail.body.params.maxstack = Max stack: -abc.detail.body.params.localregcount = Conteggio registri locali: -abc.detail.body.params.minscope = Profondit\u00e0 minima dello scope: -abc.detail.body.params.maxscope = Profondit\u00e0 massima dello scope: -abc.detail.body.params.autofill = Autocompletamento a salvataggio codice (IMPOSTAZIONE\u00a0GLOBALE) -abc.detail.body.params.autofill.experimental = ...SPERIMENTALE - -abc.detail.methodinfo.methodindex = Indice del metodo: -abc.detail.methodinfo.parameters = Parametri: -abc.detail.methodinfo.returnvalue = Tipo del valore di ritorno: - -error.methodinfo.params = Errore parametri MethodInfo -error.methodinfo.returnvalue = Errore tipo valore di ritorno MethodInfo - -abc.detail.methodinfo = MethodInfo -abc.detail.body.code = Codice MethodBody -abc.detail.body.params = Parametri MethodBody - -abc.detail.slotconst.typevalue = Tipo e valore: - -error.slotconst.typevalue = Errore tipo valore SlotConst - -message.autofill.failed = Impossibile ottenere statistiche codice per i parametri automatici nel corpo.\r\nDeselezionare Autocompletamento per evitare questo messaggio. - -info.selecttrait = Selezionare una classe e fare clic su un trait nel sorgente ActionScript per modifiche. - -button.viewgraph = Visualizza grafo -button.viewhex = Visualizza listato - -abc.traitslist.instanceinitializer = instance initializer -abc.traitslist.classinitializer = class initializer - -action.edit.experimental = (Sperimentale) - -message.action.saved = Codice salvato con successo - -error.action.save = %error% alla riga %line% - -message.confirm.remove = Sicuro di voler remuovere %item%\n e tutti gli oggetti che dipendono da esso? - -#after version 1.6.5u1: - -button.ok = OK -button.cancel = Annulla - -font.name = Nome font: -font.isbold = Grassetto: -font.isitalic = Corsivo: -font.ascent = Ascendente: -font.descent = Discendente: -font.leading = Interlinea: -font.characters = Caratteri: -font.characters.add = Aggiunta caratteri: -value.unknown = ? - -yes = s\u00ec -no = no - -errors.present = Ci sono ERRORI nel registro. Fare clic per visualizzare. -errors.none = Non ci sono errori nel registro. - -#after version 1.6.6: - -dialog.message.title = Messaggio -dialog.select.title = Selezionare un'opzione - -button.yes = S\u00ec -button.no = No - -FileChooser.openButtonText = Apri -FileChooser.openButtonToolTipText = Apri -FileChooser.lookInLabelText = Cerca in: -FileChooser.acceptAllFileFilterText = Tutti i file -FileChooser.filesOfTypeLabelText = Tipo file: -FileChooser.fileNameLabelText = Nome del file: -FileChooser.listViewButtonToolTipText = Elenco -FileChooser.listViewButtonAccessibleName = Elenco -FileChooser.detailsViewButtonToolTipText = Dettagli -FileChooser.detailsViewButtonAccessibleName = Dettagli -FileChooser.upFolderToolTipText = Su di un livello -FileChooser.upFolderAccessibleName = Su di un livello -FileChooser.homeFolderToolTipText = Home -FileChooser.homeFolderAccessibleName = Home -FileChooser.fileNameHeaderText = Nome -FileChooser.fileSizeHeaderText = Dimensione -FileChooser.fileTypeHeaderText = Tipo -FileChooser.fileDateHeaderText = Data -FileChooser.fileAttrHeaderText = Attributi -FileChooser.openDialogTitleText = Apri -FileChooser.directoryDescriptionText = Directory -FileChooser.directoryOpenButtonText = Apri -FileChooser.directoryOpenButtonToolTipText = Apri cartella selezionata -FileChooser.fileDescriptionText = File generico -FileChooser.helpButtonText = Guida -FileChooser.helpButtonToolTipText = Guida su selettore file -FileChooser.newFolderAccessibleName = Nuova cartella -FileChooser.newFolderErrorText = Errore nella creazione della cartella -FileChooser.newFolderToolTipText = Crea nuova cartella -FileChooser.other.newFolder = NuovaCartella -FileChooser.other.newFolder.subsequent = NuovaCartella.{0} -FileChooser.win32.newFolder = Nuova cartella -FileChooser.win32.newFolder.subsequent = Nuova cartella ({0}) -FileChooser.saveButtonText = Salva -FileChooser.saveButtonToolTipText = Salva file selezionato -FileChooser.saveDialogTitleText = Salva -FileChooser.saveInLabelText = Salva in: -FileChooser.updateButtonText = Aggiorna -FileChooser.updateButtonToolTipText = Aggiorna elenco cartelle - -#after version 1.6.6u2: - -FileChooser.detailsViewActionLabel.textAndMnemonic = Dettagli -FileChooser.detailsViewButtonToolTip.textAndMnemonic = Dettagli -FileChooser.fileAttrHeader.textAndMnemonic = Attributi -FileChooser.fileDateHeader.textAndMnemonic = Ultima modifica -FileChooser.fileNameHeader.textAndMnemonic = Nome -FileChooser.fileNameLabel.textAndMnemonic = Nome del file: -FileChooser.fileSizeHeader.textAndMnemonic = Dimensione -FileChooser.fileTypeHeader.textAndMnemonic = Tipo -FileChooser.filesOfTypeLabel.textAndMnemonic = Tipo file: -FileChooser.folderNameLabel.textAndMnemonic = Nome cartella: -FileChooser.homeFolderToolTip.textAndMnemonic = Home -FileChooser.listViewActionLabel.textAndMnemonic = Elenco -FileChooser.listViewButtonToolTip.textAndMnemonic = Elenco -FileChooser.lookInLabel.textAndMnemonic = Guarda in: -FileChooser.newFolderActionLabel.textAndMnemonic = Nuova cartella -FileChooser.newFolderToolTip.textAndMnemonic = Crea nuova cartella -FileChooser.refreshActionLabel.textAndMnemonic = Aggiorna -FileChooser.saveInLabel.textAndMnemonic = Salva in: -FileChooser.upFolderToolTip.textAndMnemonic = Su di un livello -FileChooser.viewMenuButtonAccessibleName = Menu visuale -FileChooser.viewMenuButtonToolTipText = Layout -FileChooser.viewMenuLabel.textAndMnemonic = Layout -FileChooser.newFolderActionLabelText = Nuova cartella -FileChooser.listViewActionLabelText = Elenco -FileChooser.detailsViewActionLabelText = Dettagli -FileChooser.refreshActionLabelText = Aggiorna -FileChooser.sortMenuLabelText = Disponi icone per -FileChooser.viewMenuLabelText = Visualizza -FileChooser.fileSizeKiloBytes = {0} KB -FileChooser.fileSizeMegaBytes = {0} MB -FileChooser.fileSizeGigaBytes = {0} GB -FileChooser.folderNameLabelText = Nome cartella: - -error.occured = Si \u00e8 verificato un errore: %error% -button.abort = Annulla -button.retry = Riprova -button.ignore = Tralascia - -font.source = Font per i sorgenti: - -#after version 1.6.7: - -menu.export = Esporta -menu.general = Generale -menu.language = Lingua - -startup.welcometo = Benvenuto a -startup.selectopen = Per iniziare fare clic su Apri nel menu oppure trascinare un file SWF su questa finestra. -menu.file.reload = Ricarica -message.confirm.reload = Questa azione annulla tutte le modifiche non salvate e carica nuovamente il file SWF.\nConfermare? - -dialog.selectbkcolor.title = Scelta colore di sfondo - - -error.font.nocharacter = Il font sorgente selezionato non contiene il carattere "%char%". - -warning.initializers = I campi statici e le costanti sono spesso valorizzati negli initializer.\nLa modifica del valore qui spesso non \u00e8 sufficiente! - - -#after version 1.7.0u1: - -menu.tools.searchMemory = Cerca SWF in memoria -button.selectbkcolor.hint = Scelta colore di sfondo per lo SWF - -ColorChooser.okText = OK -ColorChooser.cancelText = Annulla -ColorChooser.resetText = Risetta -ColorChooser.previewText = Anteprima -ColorChooser.swatchesNameText = Palette -ColorChooser.swatchesRecentText = Recente: -ColorChooser.sampleText=Testo Campione Testo Campione - -#after version 1.7.1: - -preview.play = Riproduci -preview.pause = Pausa -preview.stop = Stop - -message.confirm.removemultiple = Confermare la rimozione di %count% elementi\n e tutti gli oggetti che ne dipendono? -menu.tools.searchCache = Cerca nella cache del browser - -#after version 1.7.2u2 - -error.trait.exists = Trait con nome "%name%" gi\u00e0 presente. -button.addtrait = Aggiungi trait -button.font.embed = Incorpora... -button.yes.all = S\u00ec a tutto -button.no.all = No a tutto -message.font.add.exists = Il carattere %char% esiste gi\u00e0 nel font tag.\nSostituirlo? - -filter.gfx = File ScaleForm GFX (*.gfx) -filter.supported = Tutti i formati supportati -work.canceled = Annullato -work.restoringControlFlow = Ripristino controllo di flusso in corso -menu.advancedsettings.advancedsettings = Impostazioni avanzate -menu.recentFiles = File recenti - -#after version 1.7.4 -work.restoringControlFlow.complete = Controllo di flusso ripristinato -message.confirm.recentFileNotFound = File non trovato. Rimuovere dalla lista dei file recenti? -contextmenu.closeSwf = Chiudi SWF -menu.settings.autoRenameIdentifiers = Autorinomina identificatori -menu.file.saveasexe = Crea eseguibile... -filter.exe = File eseguibile (*.exe) - -#after version 1.8.0 -font.updateTexts = Aggiorna testi - -#after version 1.8.0u1 -menu.file.close = Chiudi -menu.file.closeAll = Chiudi tutto -menu.tools.otherTools = Altro -menu.tools.otherTools.clearRecentFiles = Pulisci file recenti -fontName.name = Nome font visualizzato: -fontName.copyright = Copyright del font: -button.preview = Anteprima -button.reset = Risetta -errors.info = Ci sono INFORMAZIONI nel log. Fare clic per visualizzare. -errors.warning = Ci sono AVVISI nel log. Fare clic per visualizzare. - -decompilationError = Errore di decompilazione - -disassemblingProgress.toString = toString -disassemblingProgress.reading = Lettura -disassemblingProgress.deobfuscating = Deoffuscamento - -contextmenu.moveTag = Sposta tag - -filter.swc = File componente SWC (*.swc) -filter.zip = File compressi (*.zip) -filter.binary = Ricerca binaria - tutti i file (*.*) - -open.error = Errore -open.error.fileNotFound = File non trovato -open.error.cannotOpen = Non \u00e8 possibile aprire il file - -node.others = altro - -#after version 1.8.1 -menu.tools.search = Ricerca testuale - -#after version 1.8.1u1 -menu.tools.timeline = Timeline - -dialog.selectcolor.title = Seleziona il colore -button.selectcolor.hint = Fare clic per selezionare il colore - -#default item name, will be used in following sentences -generictag.array.item = elemento -generictag.array.insertbeginning = Inserire %item% all'inizio -generictag.array.insertbefore = Inserire %item% prima -generictag.array.remove = Rimuovi %item% -generictag.array.insertafter = Inserire %item% dopo -generictag.array.insertend = Inserire %item% alla fine - -#after version 2.0.0 -contextmenu.expandAll = Espandi tutto - -filter.sounds = Formati audio supportati (*.wav, *.mp3) -filter.sounds.wav = Formato file Wave (*.wav) -filter.sounds.mp3 = Formato MP3 compresso (*.mp3) - -error.sound.invalid = Audio non valido. - -button.prev = Precedente -button.next = Successivo - -#after version 2.1.0 -message.action.playerglobal.title = Libreria PlayerGlobal.swc mancante -message.action.playerglobal.needed = Per effettuare modifiche immediate in AS3 la libreria "PlayerGlobal.swc" deve essere scaricato dal sito di Adobe.\r\n%adobehomepage%\r\nPremere OK per visitare la pagina di download. -message.action.playerglobal.place = Scarica la libreria PlayerGlobal(.swc) e posizionala nella cartella \r\n%libpath%\r\nScegliere OK per continuare. - -message.confirm.experimental.function = Questa funzione \u00e8 SPERIMENTALE. Ci\u00f2 significa che non \u00e8 garantito il risultato ed il file SWF pu\u00f2 essere non funzionale dopo il salvataggio. -message.confirm.donotshowagain = Non mostrare pi\u00f9 il messaggio - -menu.import = Importa -menu.file.import.text = Importa testo -import.select.directory = Selezionare cartella di importazione -error.text.import = Errore durante l'importazione del testo. Continuare? - -#after version 2.1.1 -contextmenu.removeWithDependencies = Rimuovere assieme alle dipendenze - -abc.action.find-usages = Trova invocazioni -abc.action.find-declaration = Trova dichiarazione - -contextmenu.rawEdit = Modifica raw -contextmenu.jumpToCharacter = Vai al carattere - -menu.settings.dumpView = Visualizza Dump - -menu.view = Visualizza -menu.file.view.resources = Risorse -menu.file.view.hex = Hex dump - -node.header = header - -header.signature = Firma: -header.compression = Compressione: -header.compression.lzma = LZMA -header.compression.zlib = ZLIB -header.compression.none = Nessuna compressione -header.version = Versione SWF: -header.gfx = GFX: -header.filesize = Dimensione file: -header.framerate = Frequenza frame: -header.framecount = Conteggio frame: -header.displayrect = Rect di visualizzazione: -header.displayrect.value.twips = %xmin%,%ymin% => %xmax%,%ymax% twip -header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% pixel - -#after version 2.1.2 -contextmenu.saveToFile = Salva su file -contextmenu.parseActions = Analizza azioni -contextmenu.parseABC = Analizza ABC -contextmenu.parseInstructions = Analizza istruzioni AVM2 - -#after version 2.1.3 -menu.deobfuscation = Deoffuscamento -menu.file.deobfuscation.old = Vecchio stile -menu.file.deobfuscation.new = Nuovo stile - -#after version 2.1.4 -contextmenu.openswfinside = Apri SWF incorporato -binarydata.swfInside = Rilevato SWF all'interno di questo tag di dati binari. Fare clic qui per caricarlo come sottostruttura. - -#after version 3.0.0 -button.zoomin.hint = Ingrandisci -button.zoomout.hint = Riduci -button.zoomfit.hint = Mostra tutto -button.zoomnone.hint = Scala 1:1 -button.snapshot.hint = Crea istantanea negli Appunti - -editorTruncateWarning = Testo troncato alla posizione %chars% in modalit\u00e0 debug. - -#Font name which is presented in the SWF Font tag -font.name.intag = Nome font nel tag: - -menu.debugger = Debugger -menu.debugger.switch = Debugger -menu.debugger.replacetrace = Sostituisci invocazioni di trace -menu.debugger.showlog = Visualizza log - -message.debugger = Questo debugger SWF pu\u00f2 essere utilizzato solo per stampare messaggi nella finestra di log della console del browser o alert.\r\nNon offre caratteristiche come esecuzione passo-passo, breakpoint ecc. -contextmenu.addTag = Aggiungi tag -deobfuscation.comment.tryenable = Suggerimento: \u00e8 possibile provare ad abilitare il "deoffuscamento automatico" sotto Impostazioni -deobfuscation.comment.failed = Il deoffuscamento \u00e8 attivo ma la decompilazione non \u00e8 riuscita. Se il file non \u00e8 offuscato, disattivare "Deoffuscamento automatico" potrebbe dare risultati migliori. - -#after version 4.0.2 -preview.nextframe = Frame successivo -preview.prevframe = Frame precedente -preview.gotoframe = Vai a frame... - -preview.gotoframe.dialog.title = Vai a frame -preview.gotoframe.dialog.message = Inserire il numero del frame (%min% - %max%) -preview.gotoframe.dialog.frame.error = Numero del frame non valido. Deve essere tra %min% e %max%. - -error.text.invalid.continue = Testo non valido alla riga %line%: %text% . Si desidera continuare? - -#after version 4.0.5 -contextmenu.copyTag = Copia tag -fit = adattamento -button.setAdvanceValues = Impostare i valori di avanzamento - -menu.tools.replace = Sostituzione testo - -message.confirm.close = Vi sono modifiche non salvate. Chiudere {swfName} senza salvare? -message.confirm.closeAll = Vi sono modifiche non salvate. Vuoi davvero chiudere tutti i file SWF? - -contextmenu.exportJavaSource = Esporta sorgente Java -contextmenu.exportSwfXml = Esporta SWF come XML -contextmenu.importSwfXml = Importa SWF da XML - -filter.xml = File XML (*.xml) - -#after version 4.1.0 -contextmenu.undo = Annulla - -text.align.left = Allinea a sinistra -text.align.right = Allinea a destra -text.align.center = Centrato -text.align.justify = Giustificato - -text.undo = Annulla le modifiche - -menu.file.import.xml = Importa SWF da XML -menu.file.export.xml = Esporta SWF come XML - -#after version 4.1.1 -text.align.translatex.decrease = Riduci TranslateX -text.align.translatex.increase = Incementa TranslateX -selectPreviousTag = Selezionare tag precedente -selectNextTag = Selezionare tag successivo -button.ignoreAll = Ignora tutto -menu.file.import.symbolClass = Importa classe di simbolo -text.toggleCase = Alterna maiuscole/minuscole - -#after version 5.0.2 -preview.loop = Cicla -menu.file.import.script = Importa script -contextmenu.copyTagWithDependencies = Copia tag con le dipendenze -button.replaceWithTag = Sostituisci con altro tag di carattere -button.resolveConstants = Risolvi le costanti - -#after version 5.1.0 -button.viewConstants = Visualizza le costanti -work.exported = Esportato -button.replaceAlphaChannel = Sostituire canale alfa... - -tagInfo.header.name = Nome -tagInfo.header.value = Valore -tagInfo.tagType = Tipo tag -tagInfo.characterId = Id carattere -tagInfo.offset = Offset -tagInfo.length = Lunghezza -tagInfo.bounds = Limiti -tagInfo.width = Larghezza -tagInfo.height = Altezza -tagInfo.neededCharacters = Caratteri necessari - -button.viewhexpcode = Mostra valori byte assieme alle istruzioni -taginfo.header = Informazioni tag di base - -tagInfo.dependentCharacters = Caratteri dipendenti - -#after version 5.3.0 -header.uncompressed = Non compresso -header.warning.unsupportedGfxCompression = GFX supporta solo contenuto non compresso o compresso con Zlib. -header.warning.minimumZlibVersion = La compressione zlib richiede SWF versione 6 o superiore. -header.warning.minimumLzmaVersion = la compressione LZMA richiede SWF versione 13 o superiore. - -tagInfo.codecName = Nome codec -tagInfo.exportFormat = Formato di esportazione -tagInfo.samplingRate = Frequenza di campionamento -tagInfo.stereo = Stereo -tagInfo.sampleCount = Conteggio campioni - -filter.dmg = Eseguibili Mac (*.dmg) -filter.linuxExe = Eseguibili Linux - -import.script.result = Importati %count% script. -import.script.as12warning = Importa script pu\u00f2 importare solo script AS1/2. - -error.constantPoolTooBig = Constant pool troppo grande. indice=%index%, dimensioni=%size% -error.image.alpha.invalid = Valori canale alfa non validi. - -#after version 6.0.2 -contextmenu.saveUncompressedToFile = Salva su file senza compressione -abc.traitslist.scriptinitializer = Inizializzatore script -menu.settings.autoOpenLoadedSWFs = Apri SWF caricati durante la riproduzione - -#after version 6.1.1 -menu.file.start = Avvio -menu.file.start.run = Esegui -menu.file.start.stop = Arresta -menu.file.start.debug = Debug -menu.debugging = Debug -menu.debugging.debug = Debug -menu.debugging.debug.stop = Ferma -menu.debugging.debug.pause = Pausa -menu.debugging.debug.stepOver = Passo successivo -menu.debugging.debug.stepInto = Entra nel metodo -menu.debugging.debug.stepOut = Risali dal metodo -menu.debugging.debug.continue = Continua -menu.debugging.debug.stack = Stack... -menu.debugging.debug.watch = Nuovo osservatore... - - -message.playerpath.notset = Proiettore Flash Player non trovato. Si prega di configurarne il percorso in Impostazioni avanzate / Percorsi (1). -message.playerpath.debug.notset = Proiettore Flash Player debugger di contenuto non trovato. Si prega di configurarne il percorso in Impostazioni avanzate / Percorsi (2). -message.playerpath.lib.notset = PlayerGlobal (.swc) non trovato. Si prega di configurarne il percorso in Impostazioni avanzate / Percorsi (3). - -debugpanel.header = Debug - -variables.header.registers = Registri -variables.header.locals = Variabili locali -variables.header.arguments = Argomenti -variables.header.scopeChain = Catena visibilit\u00e0 delle variabili -variables.column.name = Nome -variables.column.type = Tipo -variables.column.value = Valore - -callStack.header = Stack chiamate di funzione -callStack.header.file = File -callStack.header.line = Riga - -stack.header = Stack -stack.header.item = Voce - -constantpool.header = Pool delle costanti -constantpool.header.id = Id -constantpool.header.value = Valore - -work.running = In esecuzione -work.debugging = Debug in corso -work.debugging.instrumenting = Preparazione SWF per il debug -work.breakat = Interrompi a -work.halted = Debug iniziato, esecuzione sospesa. Aggiungi i breakpoint e scegli Continua (F5) per riprendere l'esecuzione. - -debuglog.header = Log -debuglog.button.clear = Pulisci - -# after 7.0.1 -work.debugging.wait = In attesa di connessione proiettore Flash debugger - -error.debug.listen = Impossibile ascoltare la porta %porta%. Potrebbe esserci un altro debugger in esecuzione. - -debug.break.reason.unknown = (Sconosciuto) -debug.break.reason.breakpoint = (Breakpoint) -debug.break.reason.watch = (Watch) -debug.break.reason.fault = (Fault) -debug.break.reason.stopRequest = (Richiesta di stop) -debug.break.reason.step = (Passo) -debug.break.reason.halt = (Halt) -debug.break.reason.scriptLoaded = (Script caricato) - -menu.file.start.debugpcode = Debug P-code - -# after 7.1.2 -button.replaceNoFill = Sostituisci - Aggiorna limiti... -message.warning.svgImportExperimental = Non tutte le funzioni SVG sono supportate. Controllare il registro dopo l'importazione. -message.imported.swf = Il file SWF utilizza asset da un file SWF importato:\n%url%\nCaricare gli asset da quell'indirizzo? -message.imported.swf.manually = Impossibile caricare SWF importato\n%url%\nFile o URL non esistente.\nSelezionare un file locale? - -message.warning.hexViewNotUpToDate = Hex View non aggiornato. Si prega di salvare e ricaricare il file per aggiornare la visuale. -message.font.replace.updateTexts = Sono stati sostituiti alcuni caratteri. Vuoi aggiornare i testi esistenti? - -menu.settings.simplifyExpressions = Semplifica espressioni - -#after 8.0.1 -menu.recentFiles.empty = Lista file recenti \u00e8 vuota -message.warning.outOfMemeory32BitJre = Errore di memoria esaurita. Stai eseguendo Java a 32bit su sistema operativo a 64bit. Prova con Java a 64bit. +# Copyright (C) 2010-2016 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 . + +menu.file = File +menu.file.open = Apri... +menu.file.save = Salva +menu.file.saveas = Salva come... +menu.file.export.fla = Esporta come FLA +menu.file.export.all = Esporta tutte le parti +menu.file.export.selection = Esporta selezione +menu.file.exit = Esci + +menu.tools = Strumenti +menu.tools.searchas = Cerca in tutti gli ActionScript... +menu.tools.proxy = Proxy +menu.tools.deobfuscation = Deoffuscamento +menu.tools.deobfuscation.pcode = Deoffuscamento P-code... +menu.tools.deobfuscation.globalrename = Rinomina identificatore globalmente +menu.tools.deobfuscation.renameinvalid = Rinomina identificatori non validi +menu.tools.gotoDocumentClass = Vai a document class + +menu.settings = Impostazioni +menu.settings.autodeobfuscation = Deoffuscamento automatico +menu.settings.internalflashviewer = Usa visualizzatore Flash incorporato +menu.settings.parallelspeedup = Accelerazione parallela +menu.settings.disabledecompilation = Disattiva la decompilazione (solo disassembly) +menu.settings.addtocontextmenu = Mostra FFDec nel menu contestuale per file SWF +menu.settings.language = Cambia la lingua +menu.settings.cacheOnDisk = Utilizza la cache su disco +menu.settings.gotoMainClassOnStartup = Evidenzia la document class all'avvio + +menu.help = Aiuto +menu.help.checkupdates = Controllo aggiornamenti... +menu.help.helpus = Dateci una mano! +menu.help.homepage = Visita il sito web +menu.help.about = Informazioni su... + +contextmenu.remove = Rimuovi + +button.save = Salva +button.edit = Modifica +button.cancel = Annulla +button.replace = Sostituisci... + +notavailonthisplatform = L'anteprima di questo oggetto \u00e8 disponibile solo su sistema operativo Windows. + +swfpreview = Anteprima SWF +swfpreview.internal = Anteprima SWF (visualizzatore incorporato) + +parameters = Parametri + +rename.enternew = Nuovo nome: + +rename.finished.identifier = Identificatore rinominato con successo. +rename.finished.multiname = %count% multiname rinominati. + +node.texts = text +node.images = image +node.movies = movie +node.sounds = sound +node.binaryData = BinaryData +node.fonts = font +node.sprites = sprite +node.shapes = shape +node.morphshapes = morphshape +node.buttons = button +node.frames = frame +node.scripts = script + +message.warning = Avvertenza +message.confirm.experimental = Questa procedura pu\u00f2 danneggiare il file SWF e renderlo irriproducibile.\r\nUSARE\u00a0A\u00a0PROPRIO\u00a0RISCHIO. Si desidera abilitare comunque? +message.confirm.parallel = L'esecuzione parallela velocizza il caricamento e la decompilazione ma usa pi\u00f9 memoria. +message.confirm.on = ABILITARE\u00a0questa opzione? +message.confirm.off = DISABILITARE\u00a0questa opzione? +message.confirm = Conferma + +message.confirm.autodeobfuscate = Il deoffuscamento automatico permette di decompilare codice offuscato.\r\nQuesto rallenta la decompilazione e pu\u00f2 comportare l'eliminazione di codice morto.\r\nSe il codice non \u00e8 offuscato, \u00e8 preferibile disattivare il deoffuscamento. + +message.parallel = Parallelismo +message.trait.saved = Trait salvato con successo + +message.constant.new.string = Stringa di caratteri "%value%" non presente nella tabella delle costanti. Aggiungere? +message.constant.new.string.title = Aggiunto String +message.constant.new.integer = Valore intero "%value%" not presente nella tabella delle costanti. Aggiungere? +message.constant.new.integer.title = Aggiunto Integer +message.constant.new.unsignedinteger = Valore intero senza segno "%value%" not presente nella tabella delle costanti. Aggiungere? +message.constant.new.unsignedinteger.title = Aggiunto Integer senza segno +message.constant.new.double = Valore a doppia precisione "%value%" not presente nella tabella delle costanti. Aggiungere? +message.constant.new.double.title = Aggiunto Double + +work.buffering = Buffering in corso +work.waitingfordissasembly = In attesa del disassembly +work.gettinghilights = Recupero degli highlight +work.disassembling = Disassembly in corso +work.exporting = Esportazione in corso +work.searching = Ricerca in corso +work.renaming = Rinomina in corso +work.exporting.fla = Esportazione FLA +work.renaming.identifiers = Rinomina identificatori +work.deobfuscating = Deoffuscamento +work.decompiling = Decompilazione in corso +work.gettingvariables = Lettura variabili +work.reading.swf = Lettura SWF +work.creatingwindow = Creazione finestra +work.buildingscripttree = Creazione gerarchia degli script + +work.deobfuscating.complete = Deoffuscamento completato + +message.search.notfound = Stringa "%searchtext%" non trovata. +message.search.notfound.title = Non trovato + +message.rename.notfound.multiname = Nessun multiname alla posizione corrente +message.rename.notfound.identifier = Nessun identificatore alla posizione corrente +message.rename.notfound.title = Non trovato +message.rename.renamed = %count% identificatori renominati. + +filter.images = Immagini (%extensions%) +filter.fla = Documento %version% (*.fla) +filter.xfl = Documento non compresso %version%(*.xfl) +filter.swf = File SWF (*.swf) + +error = Errore +error.image.invalid = Immagine non valida. + +error.text.invalid = Testo non valido alla riga %line%: %text% +error.file.save = Impossibile salvare il file +error.file.write = Impossibile scrivere su file +error.export = Errore durante l'esportazione + +export.select.directory = Selezionare la cartella di esportazione +export.finishedin = Esportato in %time% + +update.check.title = Controllo aggiornamenti +update.check.nonewversion = Nessuna nuova versione disponibile. + +message.helpus = Per maggiori dettagli si prega di visitare\r\n%url%\r\n +message.homepage = Visita la homepage:\r\n%url% + +proxy = Proxy +proxy.start = Avvio proxy +proxy.stop = Arresta proxy +proxy.show = Mostra proxy +exit = Esci + +panel.disassembled = Sorgente P-code +panel.decompiled = Sorgente ActionScript + +search.info = Cerca "%text%": +search.script = Script + +constants = Costanti +traits = Trait + +pleasewait = Attendere prego + +abc.detail.methodtrait = Trait di Metodo/Getter/Setter +abc.detail.unsupported = - +abc.detail.slotconsttrait = Trait Slot/Const +abc.detail.traitname = Nome: + +abc.detail.body.params.maxstack = Max stack: +abc.detail.body.params.localregcount = Conteggio registri locali: +abc.detail.body.params.minscope = Profondit\u00e0 minima dello scope: +abc.detail.body.params.maxscope = Profondit\u00e0 massima dello scope: +abc.detail.body.params.autofill = Autocompletamento a salvataggio codice (IMPOSTAZIONE\u00a0GLOBALE) +abc.detail.body.params.autofill.experimental = ...SPERIMENTALE + +abc.detail.methodinfo.methodindex = Indice del metodo: +abc.detail.methodinfo.parameters = Parametri: +abc.detail.methodinfo.returnvalue = Tipo del valore di ritorno: + +error.methodinfo.params = Errore parametri MethodInfo +error.methodinfo.returnvalue = Errore tipo valore di ritorno MethodInfo + +abc.detail.methodinfo = MethodInfo +abc.detail.body.code = Codice MethodBody +abc.detail.body.params = Parametri MethodBody + +abc.detail.slotconst.typevalue = Tipo e valore: + +error.slotconst.typevalue = Errore tipo valore SlotConst + +message.autofill.failed = Impossibile ottenere statistiche codice per i parametri automatici nel corpo.\r\nDeselezionare Autocompletamento per evitare questo messaggio. + +info.selecttrait = Selezionare una classe e fare clic su un trait nel sorgente ActionScript per modifiche. + +button.viewgraph = Visualizza grafo +button.viewhex = Visualizza listato + +abc.traitslist.instanceinitializer = instance initializer +abc.traitslist.classinitializer = class initializer + +action.edit.experimental = (Sperimentale) + +message.action.saved = Codice salvato con successo + +error.action.save = %error% alla riga %line% + +message.confirm.remove = Sicuro di voler remuovere %item%\n e tutti gli oggetti che dipendono da esso? + +#after version 1.6.5u1: + +button.ok = OK +button.cancel = Annulla + +font.name = Nome font: +font.isbold = Grassetto: +font.isitalic = Corsivo: +font.ascent = Ascendente: +font.descent = Discendente: +font.leading = Interlinea: +font.characters = Caratteri: +font.characters.add = Aggiunta caratteri: +value.unknown = ? + +yes = s\u00ec +no = no + +errors.present = Ci sono ERRORI nel registro. Fare clic per visualizzare. +errors.none = Non ci sono errori nel registro. + +#after version 1.6.6: + +dialog.message.title = Messaggio +dialog.select.title = Selezionare un'opzione + +button.yes = S\u00ec +button.no = No + +FileChooser.openButtonText = Apri +FileChooser.openButtonToolTipText = Apri +FileChooser.lookInLabelText = Cerca in: +FileChooser.acceptAllFileFilterText = Tutti i file +FileChooser.filesOfTypeLabelText = Tipo file: +FileChooser.fileNameLabelText = Nome del file: +FileChooser.listViewButtonToolTipText = Elenco +FileChooser.listViewButtonAccessibleName = Elenco +FileChooser.detailsViewButtonToolTipText = Dettagli +FileChooser.detailsViewButtonAccessibleName = Dettagli +FileChooser.upFolderToolTipText = Su di un livello +FileChooser.upFolderAccessibleName = Su di un livello +FileChooser.homeFolderToolTipText = Home +FileChooser.homeFolderAccessibleName = Home +FileChooser.fileNameHeaderText = Nome +FileChooser.fileSizeHeaderText = Dimensione +FileChooser.fileTypeHeaderText = Tipo +FileChooser.fileDateHeaderText = Data +FileChooser.fileAttrHeaderText = Attributi +FileChooser.openDialogTitleText = Apri +FileChooser.directoryDescriptionText = Directory +FileChooser.directoryOpenButtonText = Apri +FileChooser.directoryOpenButtonToolTipText = Apri cartella selezionata +FileChooser.fileDescriptionText = File generico +FileChooser.helpButtonText = Guida +FileChooser.helpButtonToolTipText = Guida su selettore file +FileChooser.newFolderAccessibleName = Nuova cartella +FileChooser.newFolderErrorText = Errore nella creazione della cartella +FileChooser.newFolderToolTipText = Crea nuova cartella +FileChooser.other.newFolder = NuovaCartella +FileChooser.other.newFolder.subsequent = NuovaCartella.{0} +FileChooser.win32.newFolder = Nuova cartella +FileChooser.win32.newFolder.subsequent = Nuova cartella ({0}) +FileChooser.saveButtonText = Salva +FileChooser.saveButtonToolTipText = Salva file selezionato +FileChooser.saveDialogTitleText = Salva +FileChooser.saveInLabelText = Salva in: +FileChooser.updateButtonText = Aggiorna +FileChooser.updateButtonToolTipText = Aggiorna elenco cartelle + +#after version 1.6.6u2: + +FileChooser.detailsViewActionLabel.textAndMnemonic = Dettagli +FileChooser.detailsViewButtonToolTip.textAndMnemonic = Dettagli +FileChooser.fileAttrHeader.textAndMnemonic = Attributi +FileChooser.fileDateHeader.textAndMnemonic = Ultima modifica +FileChooser.fileNameHeader.textAndMnemonic = Nome +FileChooser.fileNameLabel.textAndMnemonic = Nome del file: +FileChooser.fileSizeHeader.textAndMnemonic = Dimensione +FileChooser.fileTypeHeader.textAndMnemonic = Tipo +FileChooser.filesOfTypeLabel.textAndMnemonic = Tipo file: +FileChooser.folderNameLabel.textAndMnemonic = Nome cartella: +FileChooser.homeFolderToolTip.textAndMnemonic = Home +FileChooser.listViewActionLabel.textAndMnemonic = Elenco +FileChooser.listViewButtonToolTip.textAndMnemonic = Elenco +FileChooser.lookInLabel.textAndMnemonic = Guarda in: +FileChooser.newFolderActionLabel.textAndMnemonic = Nuova cartella +FileChooser.newFolderToolTip.textAndMnemonic = Crea nuova cartella +FileChooser.refreshActionLabel.textAndMnemonic = Aggiorna +FileChooser.saveInLabel.textAndMnemonic = Salva in: +FileChooser.upFolderToolTip.textAndMnemonic = Su di un livello +FileChooser.viewMenuButtonAccessibleName = Menu visuale +FileChooser.viewMenuButtonToolTipText = Layout +FileChooser.viewMenuLabel.textAndMnemonic = Layout +FileChooser.newFolderActionLabelText = Nuova cartella +FileChooser.listViewActionLabelText = Elenco +FileChooser.detailsViewActionLabelText = Dettagli +FileChooser.refreshActionLabelText = Aggiorna +FileChooser.sortMenuLabelText = Disponi icone per +FileChooser.viewMenuLabelText = Visualizza +FileChooser.fileSizeKiloBytes = {0} KB +FileChooser.fileSizeMegaBytes = {0} MB +FileChooser.fileSizeGigaBytes = {0} GB +FileChooser.folderNameLabelText = Nome cartella: + +error.occured = Si \u00e8 verificato un errore: %error% +button.abort = Annulla +button.retry = Riprova +button.ignore = Tralascia + +font.source = Font per i sorgenti: + +#after version 1.6.7: + +menu.export = Esporta +menu.general = Generale +menu.language = Lingua + +startup.welcometo = Benvenuto a +startup.selectopen = Per iniziare fare clic su Apri nel menu oppure trascinare un file SWF su questa finestra. +menu.file.reload = Ricarica +message.confirm.reload = Questa azione annulla tutte le modifiche non salvate e carica nuovamente il file SWF.\nConfermare? + +dialog.selectbkcolor.title = Scelta colore di sfondo + + +error.font.nocharacter = Il font sorgente selezionato non contiene il carattere "%char%". + +warning.initializers = I campi statici e le costanti sono spesso valorizzati negli initializer.\nLa modifica del valore qui spesso non \u00e8 sufficiente! + + +#after version 1.7.0u1: + +menu.tools.searchMemory = Cerca SWF in memoria +button.selectbkcolor.hint = Scelta colore di sfondo per lo SWF + +ColorChooser.okText = OK +ColorChooser.cancelText = Annulla +ColorChooser.resetText = Risetta +ColorChooser.previewText = Anteprima +ColorChooser.swatchesNameText = Palette +ColorChooser.swatchesRecentText = Recente: +ColorChooser.sampleText=Testo Campione Testo Campione + +#after version 1.7.1: + +preview.play = Riproduci +preview.pause = Pausa +preview.stop = Stop + +message.confirm.removemultiple = Confermare la rimozione di %count% elementi\n e tutti gli oggetti che ne dipendono? +menu.tools.searchCache = Cerca nella cache del browser + +#after version 1.7.2u2 + +error.trait.exists = Trait con nome "%name%" gi\u00e0 presente. +button.addtrait = Aggiungi trait +button.font.embed = Incorpora... +button.yes.all = S\u00ec a tutto +button.no.all = No a tutto +message.font.add.exists = Il carattere %char% esiste gi\u00e0 nel font tag.\nSostituirlo? + +filter.gfx = File ScaleForm GFX (*.gfx) +filter.supported = Tutti i formati supportati +work.canceled = Annullato +work.restoringControlFlow = Ripristino controllo di flusso in corso +menu.advancedsettings.advancedsettings = Impostazioni avanzate +menu.recentFiles = File recenti + +#after version 1.7.4 +work.restoringControlFlow.complete = Controllo di flusso ripristinato +message.confirm.recentFileNotFound = File non trovato. Rimuovere dalla lista dei file recenti? +contextmenu.closeSwf = Chiudi SWF +menu.settings.autoRenameIdentifiers = Autorinomina identificatori +menu.file.saveasexe = Crea eseguibile... +filter.exe = File eseguibile (*.exe) + +#after version 1.8.0 +font.updateTexts = Aggiorna testi + +#after version 1.8.0u1 +menu.file.close = Chiudi +menu.file.closeAll = Chiudi tutto +menu.tools.otherTools = Altro +menu.tools.otherTools.clearRecentFiles = Pulisci file recenti +fontName.name = Nome font visualizzato: +fontName.copyright = Copyright del font: +button.preview = Anteprima +button.reset = Risetta +errors.info = Ci sono INFORMAZIONI nel log. Fare clic per visualizzare. +errors.warning = Ci sono AVVISI nel log. Fare clic per visualizzare. + +decompilationError = Errore di decompilazione + +disassemblingProgress.toString = toString +disassemblingProgress.reading = Lettura +disassemblingProgress.deobfuscating = Deoffuscamento + +contextmenu.moveTag = Sposta tag + +filter.swc = File componente SWC (*.swc) +filter.zip = File compressi (*.zip) +filter.binary = Ricerca binaria - tutti i file (*.*) + +open.error = Errore +open.error.fileNotFound = File non trovato +open.error.cannotOpen = Non \u00e8 possibile aprire il file + +node.others = altro + +#after version 1.8.1 +menu.tools.search = Ricerca testuale + +#after version 1.8.1u1 +menu.tools.timeline = Timeline + +dialog.selectcolor.title = Seleziona il colore +button.selectcolor.hint = Fare clic per selezionare il colore + +#default item name, will be used in following sentences +generictag.array.item = elemento +generictag.array.insertbeginning = Inserire %item% all'inizio +generictag.array.insertbefore = Inserire %item% prima +generictag.array.remove = Rimuovi %item% +generictag.array.insertafter = Inserire %item% dopo +generictag.array.insertend = Inserire %item% alla fine + +#after version 2.0.0 +contextmenu.expandAll = Espandi tutto + +filter.sounds = Formati audio supportati (*.wav, *.mp3) +filter.sounds.wav = Formato file Wave (*.wav) +filter.sounds.mp3 = Formato MP3 compresso (*.mp3) + +error.sound.invalid = Audio non valido. + +button.prev = Precedente +button.next = Successivo + +#after version 2.1.0 +message.action.playerglobal.title = Libreria PlayerGlobal.swc mancante +message.action.playerglobal.needed = Per effettuare modifiche immediate in AS3 la libreria "PlayerGlobal.swc" deve essere scaricato dal sito di Adobe.\r\n%adobehomepage%\r\nPremere OK per visitare la pagina di download. +message.action.playerglobal.place = Scarica la libreria PlayerGlobal(.swc) e posizionala nella cartella \r\n%libpath%\r\nScegliere OK per continuare. + +message.confirm.experimental.function = Questa funzione \u00e8 SPERIMENTALE. Ci\u00f2 significa che non \u00e8 garantito il risultato ed il file SWF pu\u00f2 essere non funzionale dopo il salvataggio. +message.confirm.donotshowagain = Non mostrare pi\u00f9 il messaggio + +menu.import = Importa +menu.file.import.text = Importa testo +import.select.directory = Selezionare cartella di importazione +error.text.import = Errore durante l'importazione del testo. Continuare? + +#after version 2.1.1 +contextmenu.removeWithDependencies = Rimuovere assieme alle dipendenze + +abc.action.find-usages = Trova invocazioni +abc.action.find-declaration = Trova dichiarazione + +contextmenu.rawEdit = Modifica raw +contextmenu.jumpToCharacter = Vai al carattere + +menu.settings.dumpView = Visualizza Dump + +menu.view = Visualizza +menu.file.view.resources = Risorse +menu.file.view.hex = Hex dump + +node.header = header + +header.signature = Firma: +header.compression = Compressione: +header.compression.lzma = LZMA +header.compression.zlib = ZLIB +header.compression.none = Nessuna compressione +header.version = Versione SWF: +header.gfx = GFX: +header.filesize = Dimensione file: +header.framerate = Frequenza frame: +header.framecount = Conteggio frame: +header.displayrect = Rect di visualizzazione: +header.displayrect.value.twips = %xmin%,%ymin% => %xmax%,%ymax% twip +header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% pixel + +#after version 2.1.2 +contextmenu.saveToFile = Salva su file +contextmenu.parseActions = Analizza azioni +contextmenu.parseABC = Analizza ABC +contextmenu.parseInstructions = Analizza istruzioni AVM2 + +#after version 2.1.3 +menu.deobfuscation = Deoffuscamento +menu.file.deobfuscation.old = Vecchio stile +menu.file.deobfuscation.new = Nuovo stile + +#after version 2.1.4 +contextmenu.openswfinside = Apri SWF incorporato +binarydata.swfInside = Rilevato SWF all'interno di questo tag di dati binari. Fare clic qui per caricarlo come sottostruttura. + +#after version 3.0.0 +button.zoomin.hint = Ingrandisci +button.zoomout.hint = Riduci +button.zoomfit.hint = Mostra tutto +button.zoomnone.hint = Scala 1:1 +button.snapshot.hint = Crea istantanea negli Appunti + +editorTruncateWarning = Testo troncato alla posizione %chars% in modalit\u00e0 debug. + +#Font name which is presented in the SWF Font tag +font.name.intag = Nome font nel tag: + +menu.debugger = Debugger +menu.debugger.switch = Debugger +menu.debugger.replacetrace = Sostituisci invocazioni di trace +menu.debugger.showlog = Visualizza log + +message.debugger = Questo debugger SWF pu\u00f2 essere utilizzato solo per stampare messaggi nella finestra di log della console del browser o alert.\r\nNon offre caratteristiche come esecuzione passo-passo, breakpoint ecc. +contextmenu.addTag = Aggiungi tag +deobfuscation.comment.tryenable = Suggerimento: \u00e8 possibile provare ad abilitare il "deoffuscamento automatico" sotto Impostazioni +deobfuscation.comment.failed = Il deoffuscamento \u00e8 attivo ma la decompilazione non \u00e8 riuscita. Se il file non \u00e8 offuscato, disattivare "Deoffuscamento automatico" potrebbe dare risultati migliori. + +#after version 4.0.2 +preview.nextframe = Frame successivo +preview.prevframe = Frame precedente +preview.gotoframe = Vai a frame... + +preview.gotoframe.dialog.title = Vai a frame +preview.gotoframe.dialog.message = Inserire il numero del frame (%min% - %max%) +preview.gotoframe.dialog.frame.error = Numero del frame non valido. Deve essere tra %min% e %max%. + +error.text.invalid.continue = Testo non valido alla riga %line%: %text% . Si desidera continuare? + +#after version 4.0.5 +contextmenu.copyTag = Copia tag +fit = adattamento +button.setAdvanceValues = Impostare i valori di avanzamento + +menu.tools.replace = Sostituzione testo + +message.confirm.close = Vi sono modifiche non salvate. Chiudere {swfName} senza salvare? +message.confirm.closeAll = Vi sono modifiche non salvate. Vuoi davvero chiudere tutti i file SWF? + +contextmenu.exportJavaSource = Esporta sorgente Java +contextmenu.exportSwfXml = Esporta SWF come XML +contextmenu.importSwfXml = Importa SWF da XML + +filter.xml = File XML (*.xml) + +#after version 4.1.0 +contextmenu.undo = Annulla + +text.align.left = Allinea a sinistra +text.align.right = Allinea a destra +text.align.center = Centrato +text.align.justify = Giustificato + +text.undo = Annulla le modifiche + +menu.file.import.xml = Importa SWF da XML +menu.file.export.xml = Esporta SWF come XML + +#after version 4.1.1 +text.align.translatex.decrease = Riduci TranslateX +text.align.translatex.increase = Incementa TranslateX +selectPreviousTag = Selezionare tag precedente +selectNextTag = Selezionare tag successivo +button.ignoreAll = Ignora tutto +menu.file.import.symbolClass = Importa classe di simbolo +text.toggleCase = Alterna maiuscole/minuscole + +#after version 5.0.2 +preview.loop = Cicla +menu.file.import.script = Importa script +contextmenu.copyTagWithDependencies = Copia tag con le dipendenze +button.replaceWithTag = Sostituisci con altro tag di carattere +button.resolveConstants = Risolvi le costanti + +#after version 5.1.0 +button.viewConstants = Visualizza le costanti +work.exported = Esportato +button.replaceAlphaChannel = Sostituire canale alfa... + +tagInfo.header.name = Nome +tagInfo.header.value = Valore +tagInfo.tagType = Tipo tag +tagInfo.characterId = Id carattere +tagInfo.offset = Offset +tagInfo.length = Lunghezza +tagInfo.bounds = Limiti +tagInfo.width = Larghezza +tagInfo.height = Altezza +tagInfo.neededCharacters = Caratteri necessari + +button.viewhexpcode = Mostra valori byte assieme alle istruzioni +taginfo.header = Informazioni tag di base + +tagInfo.dependentCharacters = Caratteri dipendenti + +#after version 5.3.0 +header.uncompressed = Non compresso +header.warning.unsupportedGfxCompression = GFX supporta solo contenuto non compresso o compresso con Zlib. +header.warning.minimumZlibVersion = La compressione zlib richiede SWF versione 6 o superiore. +header.warning.minimumLzmaVersion = la compressione LZMA richiede SWF versione 13 o superiore. + +tagInfo.codecName = Nome codec +tagInfo.exportFormat = Formato di esportazione +tagInfo.samplingRate = Frequenza di campionamento +tagInfo.stereo = Stereo +tagInfo.sampleCount = Conteggio campioni + +filter.dmg = Eseguibili Mac (*.dmg) +filter.linuxExe = Eseguibili Linux + +import.script.result = Importati %count% script. +import.script.as12warning = Importa script pu\u00f2 importare solo script AS1/2. + +error.constantPoolTooBig = Constant pool troppo grande. indice=%index%, dimensioni=%size% +error.image.alpha.invalid = Valori canale alfa non validi. + +#after version 6.0.2 +contextmenu.saveUncompressedToFile = Salva su file senza compressione +abc.traitslist.scriptinitializer = Inizializzatore script +menu.settings.autoOpenLoadedSWFs = Apri SWF caricati durante la riproduzione + +#after version 6.1.1 +menu.file.start = Avvio +menu.file.start.run = Esegui +menu.file.start.stop = Arresta +menu.file.start.debug = Debug +menu.debugging = Debug +menu.debugging.debug = Debug +menu.debugging.debug.stop = Ferma +menu.debugging.debug.pause = Pausa +menu.debugging.debug.stepOver = Passo successivo +menu.debugging.debug.stepInto = Entra nel metodo +menu.debugging.debug.stepOut = Risali dal metodo +menu.debugging.debug.continue = Continua +menu.debugging.debug.stack = Stack... +menu.debugging.debug.watch = Nuovo osservatore... + + +message.playerpath.notset = Proiettore Flash Player non trovato. Si prega di configurarne il percorso in Impostazioni avanzate / Percorsi (1). +message.playerpath.debug.notset = Proiettore Flash Player debugger di contenuto non trovato. Si prega di configurarne il percorso in Impostazioni avanzate / Percorsi (2). +message.playerpath.lib.notset = PlayerGlobal (.swc) non trovato. Si prega di configurarne il percorso in Impostazioni avanzate / Percorsi (3). + +debugpanel.header = Debug + +variables.header.registers = Registri +variables.header.locals = Variabili locali +variables.header.arguments = Argomenti +variables.header.scopeChain = Catena visibilit\u00e0 delle variabili +variables.column.name = Nome +variables.column.type = Tipo +variables.column.value = Valore + +callStack.header = Stack chiamate di funzione +callStack.header.file = File +callStack.header.line = Riga + +stack.header = Stack +stack.header.item = Voce + +constantpool.header = Pool delle costanti +constantpool.header.id = Id +constantpool.header.value = Valore + +work.running = In esecuzione +work.debugging = Debug in corso +work.debugging.instrumenting = Preparazione SWF per il debug +work.breakat = Interrompi a +work.halted = Debug iniziato, esecuzione sospesa. Aggiungi i breakpoint e scegli Continua (F5) per riprendere l'esecuzione. + +debuglog.header = Log +debuglog.button.clear = Pulisci + +# after 7.0.1 +work.debugging.wait = In attesa di connessione proiettore Flash debugger + +error.debug.listen = Impossibile ascoltare la porta %porta%. Potrebbe esserci un altro debugger in esecuzione. + +debug.break.reason.unknown = (Sconosciuto) +debug.break.reason.breakpoint = (Breakpoint) +debug.break.reason.watch = (Watch) +debug.break.reason.fault = (Fault) +debug.break.reason.stopRequest = (Richiesta di stop) +debug.break.reason.step = (Passo) +debug.break.reason.halt = (Halt) +debug.break.reason.scriptLoaded = (Script caricato) + +menu.file.start.debugpcode = Debug P-code + +# after 7.1.2 +button.replaceNoFill = Sostituisci - Aggiorna limiti... +message.warning.svgImportExperimental = Non tutte le funzioni SVG sono supportate. Controllare il registro dopo l'importazione. +message.imported.swf = Il file SWF utilizza asset da un file SWF importato:\n%url%\nCaricare gli asset da quell'indirizzo? +message.imported.swf.manually = Impossibile caricare SWF importato\n%url%\nFile o URL non esistente.\nSelezionare un file locale? + +message.warning.hexViewNotUpToDate = Hex View non aggiornato. Si prega di salvare e ricaricare il file per aggiornare la visuale. +message.font.replace.updateTexts = Sono stati sostituiti alcuni caratteri. Vuoi aggiornare i testi esistenti? + +menu.settings.simplifyExpressions = Semplifica espressioni + +#after 8.0.1 +menu.recentFiles.empty = Lista file recenti \u00e8 vuota +message.warning.outOfMemeory32BitJre = Errore di memoria esaurita. Stai eseguendo Java a 32bit su sistema operativo a 64bit. Prova con Java a 64bit.