diff --git a/CHANGELOG.md b/CHANGELOG.md index 90e3e261e..e4b45d5e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,14 +35,14 @@ All notable changes to this project will be documented in this file. - font normalizer uses 1024em ([#2661]) - null pointer on null caret in variable marker - push commands in as2 left in code ([#2654]) -- deadlock on getcharacters vs drawframe ([#2492]) +- deadlock on getCharacters vs drawFrame ([#2492]) - nullpointer on as3 deobfuscation - as3 deobfuscation - null values instead of registers ([#2568], [#2665]) - stackoverflow on circular importassets ([#2666]) - allow add breakpoints on large classes ([#2672]) - unable to reset JNA temp directory ([#2675]) - svg shape export - use proper winding -- properly normalize fonts in defineedittexts, kerning +- properly normalize fonts in DefineEditTexts, kerning - properly draw edittext border, normalize size - illegal argument exception on creating morphshape from svg ([#2676]) - respect nofill argument in shape CLI SVG export ([#2681]) diff --git a/README.md b/README.md index f4ec9a9e1..d617f8bdd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # JPEXS Free Flash Decompiler ![Build passing badge](https://github.com/jindrapetrik/jpexs-decompiler/actions/workflows/build.yml/badge.svg?branch=dev) +English | [简体中文](README_zh.md) + Open Source Flash SWF decompiler and editor. Extract resources, convert SWF to FLA, edit ActionScript, replace images, sounds, texts and fonts. Various output formats available. Works with Java on Windows, Linux and macOS. ## Application description and features @@ -120,7 +122,7 @@ The application was made in Czech Republic. ### Translators * **Jaume Badiella Aguilera** - catalan translation * **Capasha** - swedish translation -* **王晨旭** (Chenxu Wang), **晓之车**, **安安**, **流水渺渺**, **老biu** - chinese translation +* **王晨旭** (Chenxu Wang), **晓之车**, **安安**, **Liushui**, **老biu** - chinese translation * **focus** - russian translation * **honfika** - hungarian translation * **kalip** - italian translation diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 000000000..f00431a4c --- /dev/null +++ b/README_zh.md @@ -0,0 +1,186 @@ +# JPEXS 免费 Flash 反编译器 +![Build passing badge](https://github.com/jindrapetrik/jpexs-decompiler/actions/workflows/build.yml/badge.svg?branch=dev) + +[English](README.md) | 简体中文 + +这是一款开源的 Flash SWF 反编译器和编辑器。能够提取资源,将 SWF 文件转换为 FLA 文件,编辑 ActionScript 代码,替换图片、声音、文本和字体。能够提供多种输出格式。通过 Java 环境运行于 Windows、Linux 和 macOS 系统上。 + +## 应用描述与功能 +有关软件使用方法、功能列表等信息,请访问 [FFDec 维基](https://github.com/jindrapetrik/jpexs-decompiler/wiki)。 + +## Free-Decompiler.com 网站 +过去(2018 年之前),我们使用 *free-decompiler.com* 域名作为主页,源代码则存储在 GitHub 上。现在,我们已将所有信息(问题跟踪器除外)迁移到了 GitHub。 + +## 下载应用 +如需下载该应用程序,请前往 [latest release](https://github.com/jindrapetrik/jpexs-decompiler/releases/latest) 页面。 +旧版本和每夜构建版本可在 [releases](https://github.com/jindrapetrik/jpexs-decompiler/releases) 页面获取。 + +### 如何安装 +请参阅 [维基百科](https://github.com/jindrapetrik/jpexs-decompiler/wiki/Installation) 的安装部分。 + +## 源代码 +### 如何获取源代码 +您可以使用以下命令创建源代码的本地副本: +``` +git clone https://github.com/jindrapetrik/jpexs-decompiler.git +``` +此操作假定您的系统中已经安装了 Git 。 + +### 分支 +Git 版本控制管理器管理着多个代码分支。我们使用其中两个主要分支。 + +* `master` - 已发布的 “稳定” 版本 +* `dev` - 开发者的最新更改 - “每夜构建”版本从此分支发布 + +您可以使用以下 git 命令切换到 `dev` 分支: +``` +git checkout dev +``` + +### GIT 建议 +建议安装 [GIT] 命令行可执行文件。构建脚本使用 GIT 将版本号包含在二进制文件中。(对于 Windows 系统,您必须在 GIT 安装过程中配置 Windows 命令行。) + +### Netbeans 工程 + +源代码包含 Netbeans 项目,因此您可以在 [Netbeans IDE] 中打开它。然后,您可以使用 IDE 中诸如 “运行”、“构建”、“调试”、“清理” 和 “构建” 等标准操作。其他特定任务可以通过 build.xml 中的菜单执行(参见 Ant 部分)。 + +### Ant +如果没有 Netbeans,您也可以使用 Apache Ant 构建源代码。 +安装 Ant 之后,将最好其添加到您的 PATH 变量中。 +打开命令行并导航到源代码目录, +要运行应用程序,请输入以下命令执行 “运行” 任务: +``` +ant run +``` +若仅需构建应用程序,请执行 “构建” 任务: +``` +ant build +``` + +### 构建库 + +还有一些库也需要构建。这些库放在 “libsrc” 目录中。 +* **FFDec_lib** - 进行反编译、SWF 解析、导出等核心功能。**该库会随主项目自动构建,但也可以使用其自身的 Ant 脚本单独构建。** +* **jpacker** - 用于压缩 JavaScript Canvas 的脚本(Netbeans/Ant 工程) +* **jpproxy** - FFDec 的代理部分(Netbeans/Ant project) +* **jsyntaxpane** - 代码编辑器(Netbeans/Apache Maven 工程) +* **LZMA** - 用于 SWF 文件的压缩(Netbeans/Ant 工程) +* **nellymoser** - 用于 Nelly Moser 音效的解码(Netbeans/Ant 工程) +* **Swf2Exe** - “保存为 EXE 文件” 功能的占位符(Delphi 7 工程) +* **ttf** - 用于 TTF 字体的导出(Netbeans/Ant 工程) +* **gnujpdf** - 用于 PDF 文件的导出(Netbeans/Ant 工程) + +## Docker +我们有用于无头运行的 `Dockerfile`,这样就无需在本地安装 Java 或 FFDec。 +(原始脚本来自:Mahdi Lazraq) +### 构建 +``` +docker build -t ffdec . +``` +### 用法 +FFDec 命令行(CLI) 是入口点,因此您可以直接传递参数: +``` +docker run --rm -v ./input:/work/input -v ./output:/work/output ffdec [args] +``` + +## 更新日志 +所有重要变更均列于 [CHANGELOG.md](CHANGELOG.md) 文件中。 + +## 部署 + +### 每夜构建 +当提交被 推送/合并 到 `dev` 分支时,GitHub Actions CI 会自动创建一个新的预发布版本。 +这些预发布版本被称为 每夜构建(nightly build)。在发布新的每夜构建版本后,之前的每夜构建版本就会被移除。 + +### 稳定版本 +当在 master 分支中使用 `versionx.y.z` 格式的标签标记修订版本时,GitHub Actions CI 会自动创建一个新的稳定版本。 + +## 贡献 + +请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 文件,以了解我们的行为准则详情以及提交拉取请求的流程。 + +## 版本控制 + +版本号采用 `x.y.z` 格式,例如 `9.1.2`。 +有关可用版本,请参阅 [此存储库上的标签](https://github.com/jindrapetrik/jpexs-decompiler/tags)。 + +每夜构建版本带有额外的 `_nightlyN` 后缀,其中 `N` 是一个数字,每次(自动)发布每夜构建版本时都会递增,并且与 `x.y.z` 编号无关(这意味着发布稳定版本时,每夜构建版本的编号不会重置为 0)。 +较早的每夜构建版本 *无法* 通过 Git 标签获取。 + +## 作者 +反编译器最初由 **Jindra Petřík**(又名 **JPEXS**)编写。 +该应用制作于捷克共和国。 + +### 开发者 +* **JPEXS** - 项目负责人、反编译器开发、网站主管理员、GitHub 帐户管理员、组织管理员 +* **honfika** - 反编译器开发 +* **Paolo Cancedda** - 前开发者 +* ...以及来自 GitHub 和 Google Code 的其他人 + +### 翻译者 +* **Jaume Badiella Aguilera** - 加泰罗尼亚语翻译 +* **Capasha** - 瑞典语翻译 +* **王晨旭** (Chenxu Wang), **晓之车**, **安安**, **Liushui**, **老biu** - 中文翻译 +* **focus** - 俄语翻译 +* **honfika** - 匈牙利语翻译 +* **kalip** - 意大利语翻译 +* **Krock** - 德语翻译 +* **Laurent LOUVET** - 法语翻译 +* **MaGiC** - 葡萄牙语翻译 +* **martinkoza** - 波兰语翻译 +* **Osman ÖZ** - 土耳其语翻译 +* **pepka** - 乌克兰语、荷兰语翻译 +* **poxyran** - 西班牙语翻译 +* **realmaster42**, **alimsoftware** - 葡萄牙语(巴西)翻译 +* **Rtsjx** - 中文翻译 +* **koiru** - 日语翻译 +* **J. Kramer** - 荷兰语翻译 +* **Andrew Poženel** - 斯洛文尼亚语翻译 +* **GitHub Copilot (Claude AI)** - 德语、斯洛伐克语翻译 + +## 联系 +如果您想报告问题或提出新功能请求,请使用我们的问题跟踪系统:[https://www.free-decompiler.com/flash/issues](https://www.free-decompiler.com/flash/issues) + +在报告之前,您应该已经在维基百科上查看过 [常见问题解答(FAQ)](https://github.com/jindrapetrik/jpexs-decompiler/wiki/FAQ) 部分了。 +另外,也请 [参阅维基百科中的已知问题列表](https://github.com/jindrapetrik/jpexs-decompiler/wiki/Known-problems)。 + +### 邮件联系 +JPEXS 开发者的紧急联系邮箱是 `jindra.petrik@gmail.com`。 +但我们更倾向于使用问题跟踪系统进行联系。 + +## 许可协议 + 致谢 +### 应用 + +FFDec 应用程序采用 GNU GPL v3(GPL-3.0 或更高版本)许可证,详情请参阅 [license.txt](license.txt) 文件。它使用了以下库的修改代码: + +* [JSyntaxPane] (代码编辑器) - Apache License 2.0 + +并且链接了以下的库: + +* [Java Native Access - JNA] (注册表关联,进程内存读取) - LGPL +* [Insubstantial] (Substance Look and Feel,Flamingo Ribbon 组件) - Revised BSD +* [javactivex] (Flash Player ActiveX 的嵌入) - LGPLv3 +* [flashdebugger library] (调试 ActionScript) - LGPLv3 +* FFDec Library (LGPLv3) - 参阅如下 + +应用程序还使用了 [Silk icons pack]、[Silk companion 1]、[FatCow icons pack] 和 [Aha-Soft icons pack] 中的一些图标。 + +对于 EXE 启动器,我们使用 [Launch5j] - MIT。 + +## 库 +有关 FFDec 库的更多信息,请参阅 [库 README](libsrc/ffdec_lib/README.md) 文件。 + +[GIT]: http://git-scm.com/downloads +[Netbeans IDE]: http://www.netbeans.org/ +[Apache Ant]: http://ant.apache.org/ +[Launch5j]: https://github.com/lordmulder/Launch5j +[NSIS]: http://nsis.sourceforge.net/ +[JSyntaxPane]: https://code.google.com/p/jsyntaxpane/ +[Java Native Access - JNA]: https://github.com/twall/jna +[Insubstantial]: http://shemnon.com/speling/2011/04/insubstantial-62-release.html +[javactivex]:https://github.com/jindrapetrik/javactivex +[flashdebugger library]: https://github.com/jindrapetrik/flashdebugger +[Silk icons pack]: http://www.famfamfam.com/lab/icons/silk/ +[Silk companion 1]: http://damieng.com/creative/icons/silk-companion-1-icons +[FatCow icons pack]: http://www.fatcow.com/free-icons +[Aha-Soft icons pack]: http://www.aha-soft.com diff --git a/altsigner/pom.xml b/altsigner/pom.xml index 52c34f8bb..f186fa24c 100644 --- a/altsigner/pom.xml +++ b/altsigner/pom.xml @@ -64,7 +64,7 @@ org.bouncycastle bcprov-jdk18on - 1.83 + 1.84 \ No newline at end of file diff --git a/cicd_scripts/update_changelog.php b/cicd_scripts/update_changelog.php index 4d8b7d1cd..75bb3acbe 100644 --- a/cicd_scripts/update_changelog.php +++ b/cicd_scripts/update_changelog.php @@ -40,7 +40,7 @@ if ($result !== 0) { exit(1); } - +$output = []; $result = 0; exec('git log ' . $version1 . '..' . $version2 . ' --pretty=format:"%s%n%b%n---SPLIT---" --reverse', $output, $result); if ($result !== 0) { @@ -99,7 +99,7 @@ foreach ($messages as $message) { if (array_key_exists($type, $changelog_types)) { $changelog[$type][] = $desc; } - } + } } $result = ""; diff --git a/lib/flacomdoc.jar b/lib/flacomdoc.jar index eb4041b73..6218cc825 100644 Binary files a/lib/flacomdoc.jar and b/lib/flacomdoc.jar differ diff --git a/lib/jsyntaxpane-0.9.5.jar b/lib/jsyntaxpane-0.9.5.jar index 2d610772d..7098665e9 100644 Binary files a/lib/jsyntaxpane-0.9.5.jar and b/lib/jsyntaxpane-0.9.5.jar differ diff --git a/libsrc/ffdec_lib/lib/flacomdoc.jar b/libsrc/ffdec_lib/lib/flacomdoc.jar index eb4041b73..6218cc825 100644 Binary files a/libsrc/ffdec_lib/lib/flacomdoc.jar and b/libsrc/ffdec_lib/lib/flacomdoc.jar differ diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/FontNormalizer.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/FontNormalizer.java index 6ea995584..80a4a31b9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/FontNormalizer.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/FontNormalizer.java @@ -390,7 +390,7 @@ public class FontNormalizer { private Set getDefineEditTextFonts(DefineEditTextTag text) { Set ret = new LinkedHashSet<>(); TextStyle style = new TextStyle(); - if (text.fontClass != null) { + if (text.hasFontClass) { style.font = text.getSwf().getFontByClass(text.fontClass); } else { style.font = text.getSwf().getFont(text.fontId); @@ -513,7 +513,7 @@ public class FontNormalizer { private void scaleDefineEditTextFonts(DefineEditTextTag text, Map fontNewScale, boolean inPlace, Map outTexts) { String str = ""; TextStyle style = new TextStyle(); - if (text.fontClass != null) { + if (text.hasFontClass) { style.font = text.getSwf().getFontByClass(text.fontClass); } else { style.font = text.getSwf().getFont(text.fontId); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 9ec42418b..c4cb27a26 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -3165,25 +3165,22 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { } /** - * Makes scriptpacks unique. Unique = no two packs with same classpath + * Checks scriptpacks whether they are unique. Unique = no two packs with same classpath * exist. * * @param packs List of ScriptPacks * @return List of unique ScriptPacks */ - private List uniqueAS3Packs(List packs) { - List ret = new ArrayList<>(); + private void checkUniqueAS3Packs(List packs) { Set classPaths = new HashSet<>(); for (ScriptPack item : packs) { ClassPath key = item.getClassPath(); if (classPaths.contains(key) && item.isSimple) { - logger.log(Level.SEVERE, "Duplicate pack path found ({0})!", key); + logger.log(Level.WARNING, "Duplicate scriptpack path found ({0})!", key); } else { - classPaths.add(key); - ret.add(item); + classPaths.add(key); } - } - return ret; + } } /** @@ -3205,7 +3202,8 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { for (ABCContainerTag abcTag : abcList) { packs.addAll(abcTag.getABC().getScriptPacks(null, allAbcList)); } - return uniqueAS3Packs(packs); + checkUniqueAS3Packs(packs); + return packs; } /** 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 76c02e764..5adcfa062 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 @@ -2031,7 +2031,9 @@ public class AVM2Code implements Cloneable { if (code.get(ip + plus + 3).definition instanceof SetPropertyIns) { functionName = abc.constants.getMultiname(code.get(ip + plus + 3).operands[0]).getName(usedDeobfuscations, abc, abc.constants, fullyQualifiedNames, true, true); localScopeStack.pop(); // with - output.remove(output.size() - 1); // with + stack.finishBlock(output); + stack.moveToStack(output); + output.remove(output.size() - 1); // with ip = ip + plus + 4; // +1 below } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AbcIndexing.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AbcIndexing.java index 5f4c8c969..de5336fa7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AbcIndexing.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AbcIndexing.java @@ -47,7 +47,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.WeakHashMap; /** * Indexing of ABCs for faster access. Indexes ABC classes for faster class and @@ -1104,6 +1103,9 @@ public final class AbcIndexing { */ protected void indexTraits(ABC abc, int name_index, Traits ts, Map map, Map mapNs, Map> mapAmbiguous, int scriptIndex) { for (Trait t : ts.traits) { + if (t.deleted) { + continue; + } ValueKind propValue = null; if (t instanceof TraitSlotConst) { TraitSlotConst tsc = (TraitSlotConst) t; @@ -1233,6 +1235,9 @@ public final class AbcIndexing { indexTraits(abc, 0, abc.script_info.get(i).traits, null, scriptProperties, scriptAmbiguousProperties, i); for (int t = 0; t < abc.script_info.get(i).traits.traits.size(); t++) { Trait tr = abc.script_info.get(i).traits.traits.get(t); + if (tr.deleted) { + continue; + } if (tr instanceof TraitClass) { TraitClass tc = (TraitClass) tr; InstanceInfo ii = abc.instance_info.get(tc.class_info); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/CallAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/CallAVM2Item.java index 94aa74a13..8d42f22fe 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/CallAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/CallAVM2Item.java @@ -224,7 +224,7 @@ public class CallAVM2Item extends AVM2Item { } if (callable instanceof TypeItem && propIndex != -1 && arguments.size() == 1) { - AVM2Instruction ins = NameAVM2Item.generateCoerce(localData, generator, callable); + AVM2Instruction ins = NameAVM2Item.generateConvert(localData, generator, callable); if (ins != null) { return toSourceMerge(localData, generator, arguments, ins); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NameAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NameAVM2Item.java index c339c63cc..230dfa711 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NameAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NameAVM2Item.java @@ -352,6 +352,45 @@ public class NameAVM2Item extends AssignableAVM2Item { } return ins; } + + /** + * Generates convert. + * @param localData Local data + * @param generator Generator + * @param ttype Target type + * @return Convert instruction + * @throws CompilationException On compilation error + */ + public static AVM2Instruction generateConvert(SourceGeneratorLocalData localData, SourceGenerator generator, GraphTargetItem ttype) throws CompilationException { + if (ttype instanceof UnresolvedAVM2Item) { + ttype = ((UnresolvedAVM2Item) ttype).resolved; + } + AVM2Instruction ins = null; + switch (ttype.toString()) { + case "int": + ins = ins(AVM2Instructions.ConvertI); + break; + case "String": + ins = ins(AVM2Instructions.ConvertS); + break; + case "Boolean": + ins = ins(AVM2Instructions.ConvertB); + break; + case "uint": + ins = ins(AVM2Instructions.ConvertU); + break; + case "Number": + ins = ins(AVM2Instructions.ConvertD); + break; + case "float": + ins = ins(AVM2Instructions.ConvertF); + break; + case "float4": + ins = ins(AVM2Instructions.ConvertF4); + break; + } + return ins; + } private List toSource(SourceGeneratorLocalData localData, SourceGenerator generator, boolean needsReturn) throws CompilationException { addTraitUsage(localData, localData.callStack); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java index e490dc250..baa384a83 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java @@ -342,8 +342,10 @@ public class PropertyAVM2Item extends AssignableAVM2Item { boolean found = false; String nsName = ns.getName(propValueAbc.constants).toRawString(); while (ci != null) { - DottedChain clsName = ci.abc.instance_info.get(ci.index).getName(ci.abc.constants).getNameWithNamespace(new HashSet<>(), ci.abc, ci.abc.constants, false); - String clsNsName = clsName.isTopLevel() ? clsName.getLast() : clsName.getWithoutLast().toRawString() + ":" + clsName.getLast(); + DottedChain clsFullName = ci.abc.instance_info.get(ci.index).getName(ci.abc.constants).getNameWithNamespace(new HashSet<>(), ci.abc, ci.abc.constants, false); + DottedChain clsPkg = clsFullName.getWithoutLast(); + String clsName = clsFullName.getLast(); + String clsNsName = clsPkg.isTopLevel() ? clsName : clsPkg.toRawString() + ":" + clsName; if (Objects.equals(nsName, clsNsName)) { found = true; break; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java index ba6ae4960..96e99cd9e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java @@ -433,6 +433,8 @@ public class ActionGraph extends Graph { targetStartItem = st; target = new DirectValueActionItem(null, null, 0, st.target, new ArrayList<>()); } + } else if (targetStart > -1) { + targetEnd = t; } } if (it instanceof SetTarget2ActionItem) { @@ -445,9 +447,15 @@ public class ActionGraph extends Graph { targetStartItem = st; target = st.target; } + } else if (targetStart > -1) { + targetEnd = t; } } + if (it instanceof TellTargetActionItem && targetStart > -1) { + targetEnd = t; + } + if (targetStart > -1 && targetEnd > -1) { List newlist = new ArrayList<>(); for (int i = 0; i < targetStart; i++) { @@ -459,7 +467,7 @@ public class ActionGraph extends Graph { } newlist.add(new TellTargetActionItem(targetStartItem.getSrc(), targetStartItem.getLineStartItem(), target, tellist)); //TODO: maybe set nested flag - for (int i = targetEnd + 1; i < list.size(); i++) { + for (int i = targetEnd + (it instanceof TellTargetActionItem ? 0 : 1); i < list.size(); i++) { newlist.add(list.get(i)); } list.clear(); @@ -467,7 +475,7 @@ public class ActionGraph extends Graph { targetStart = -1; targetEnd = -1; target = null; - t = 0; + t = -1; } } for (int t = 1/*not first*/; t < list.size(); t++) { @@ -1043,7 +1051,7 @@ public class ActionGraph extends Graph { ActionSecondPassData spd = new ActionSecondPassData(); Set processedIfs = new HashSet<>(); checkSecondPassSwitches(localData, loops, throwStates, spd.switchCases, spd.switchBreaks, processedIfs, list, spd.switchParts, spd.switchOnFalseParts, spd.switchCaseExpressions); - + return spd; } @@ -1174,7 +1182,7 @@ public class ActionGraph extends Graph { allSwitchParts.add(switchParts); allSwitchOnFalseParts.add(switchOnFalseParts); allSwitchExpressions.add(switchExpressions); - allSwitchCases.add(switchCases); + allSwitchCases.add(switchCases); try { allSwitchBreaks.add(getMostCommonPart(localData, switchCases, loops, throwStates, new ArrayList<>())); } catch (InterruptedException ex) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/FunctionActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/FunctionActionItem.java index cc1af9ef9..b64ecddca 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/FunctionActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/FunctionActionItem.java @@ -496,57 +496,57 @@ public class FunctionActionItem extends ActionItem { } int regCount = 0; - if (actions != null && !actions.isEmpty()) { - localDataCopy.inFunction++; + + localDataCopy.inFunction++; - for (VariableActionItem v : variables) { - String varName = v.getVariableName(); - GraphTargetItem stored = v.getStoreValue(); - if (needsFun2) { - if (v.isDefinition() && !registerNames.contains(varName) && !deeplyUsedVariableNames.contains(varName) - && !hasEval) { - registerNames.add(varName); - } + for (VariableActionItem v : variables) { + String varName = v.getVariableName(); + GraphTargetItem stored = v.getStoreValue(); + if (needsFun2) { + if (v.isDefinition() && !registerNames.contains(varName) && !deeplyUsedVariableNames.contains(varName) + && !hasEval) { + registerNames.add(varName); } + } - if (registerNames.contains(varName)) { - if (stored != null) { - v.setBoxedValue(new StoreRegisterActionItem(null, null, new RegisterNumber(registerNames.indexOf(varName), varName), stored, false)); - } else { - v.setBoxedValue(new DirectValueActionItem(new RegisterNumber(registerNames.indexOf(varName), varName))); - } - } else if (v.isDefinition()) { - v.setBoxedValue(new DefineLocalActionItem(null, null, ((ActionSourceGenerator) generator).pushConstTargetItem(varName), stored)); - } else if (stored != null) { - v.setBoxedValue(new SetVariableActionItem(null, null, ((ActionSourceGenerator) generator).pushConstTargetItem(varName), stored)); + if (registerNames.contains(varName)) { + if (stored != null) { + v.setBoxedValue(new StoreRegisterActionItem(null, null, new RegisterNumber(registerNames.indexOf(varName), varName), stored, false)); } else { - v.setBoxedValue(new GetVariableActionItem(null, null, ((ActionSourceGenerator) generator).pushConstTargetItem(varName))); + v.setBoxedValue(new DirectValueActionItem(new RegisterNumber(registerNames.indexOf(varName), varName))); } - - } - for (int i = 1 /* zero is not preloaded*/; i < registerNames.size(); i++) { - localDataCopy.registerVars.put(registerNames.get(i), i); + } else if (v.isDefinition()) { + v.setBoxedValue(new DefineLocalActionItem(null, null, ((ActionSourceGenerator) generator).pushConstTargetItem(varName), stored)); + } else if (stored != null) { + v.setBoxedValue(new SetVariableActionItem(null, null, ((ActionSourceGenerator) generator).pushConstTargetItem(varName), stored)); + } else { + v.setBoxedValue(new GetVariableActionItem(null, null, ((ActionSourceGenerator) generator).pushConstTargetItem(varName))); } + } + for (int i = 1 /* zero is not preloaded*/; i < registerNames.size(); i++) { + localDataCopy.registerVars.put(registerNames.get(i), i); + } + + if (actions != null && !actions.isEmpty()) { ret.addAll(asGenerator.toActionList(asGenerator.generate(localDataCopy, actions))); + } + regCount = registerNames.size(); - regCount = registerNames.size(); - - //some temporary registers can exceed variable+param count - for (GraphSourceItem a : ret) { - if (a instanceof ActionPush) { - ActionPush apu = (ActionPush) a; - for (Object o : apu.values) { - if (o instanceof RegisterNumber) { - RegisterNumber rn = (RegisterNumber) o; - if (rn.number >= regCount) { - regCount++; - } + //some temporary registers can exceed variable+param count + for (GraphSourceItem a : ret) { + if (a instanceof ActionPush) { + ActionPush apu = (ActionPush) a; + for (Object o : apu.values) { + if (o instanceof RegisterNumber) { + RegisterNumber rn = (RegisterNumber) o; + if (rn.number >= regCount) { + regCount++; } } } } - } + } int len = Action.actionsToBytes(asGenerator.toActionList(ret), false, SWF.DEFAULT_VERSION).length; if (len > 0xFFFF) { throw new CompilationException("Function body is too large to fit into UI16.", line); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionSetMember.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionSetMember.java index 90bb6896e..44f655e1b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionSetMember.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionSetMember.java @@ -188,7 +188,7 @@ public class ActionSetMember extends Action { ((GetMemberActionItem) ((DecrementActionItem) value).object).object = ((GetMemberActionItem) ((DecrementActionItem) value).object).object.getThroughDuplicate(); cleanupTemp(((GetMemberActionItem) ((DecrementActionItem) value).object).object, object, output, stack); if (setter) { - stack.addToOutput(new PreDecrementActionItem(action, lineStartAction, ((IncrementActionItem) value).object.getThroughDuplicate())); + stack.addToOutput(new PreDecrementActionItem(action, lineStartAction, ((DecrementActionItem) value).object.getThroughDuplicate())); } else { stack.addToOutput(new PostDecrementActionItem(action, lineStartAction, ((DecrementActionItem) value).object.getThroughDuplicate())); } @@ -252,8 +252,14 @@ public class ActionSetMember extends Action { } finally { if (setter) { stack.finishBlock(output); - stack.push(output.remove(output.size() - 1)); - stack.moveToStack(output); + // Guard against an empty output: if the try block exited via an + // exception before producing a statement, removing from an empty + // list would throw IndexOutOfBoundsException here and mask the + // original exception. Mirrors the check used in cleanupTemp(). + if (!output.isEmpty()) { + stack.push(output.remove(output.size() - 1)); + stack.moveToStack(output); + } } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index 3c419c85c..68ba91f67 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -1237,6 +1237,14 @@ public final class Configuration { @ConfigurationCategory("display") public static ConfigurationItem useMinimumStrokeWidth1Px = null; + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("display") + public static ConfigurationItem showLoadingSpinner = null; + + @ConfigurationDefaultString("") + @ConfigurationName("xmlExport.formats") + public static ConfigurationItem lastSelectedXmlExportFormats = null; + private static Map configurationDescriptions = new LinkedHashMap<>(); private static Map configurationTitles = new LinkedHashMap<>(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/LegacyConfigurationStorage.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/LegacyConfigurationStorage.java index 658413f86..4c0bfdff1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/LegacyConfigurationStorage.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/LegacyConfigurationStorage.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.configuration; +import com.jpexs.helpers.AllowedObjectInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -42,7 +43,7 @@ public class LegacyConfigurationStorage implements ConfigurationStorage { @Override public Map loadFromFile(String file) { - try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) { + try (ObjectInputStream ois = new AllowedObjectInputStream(new FileInputStream(file))) { @SuppressWarnings("unchecked") Map cfg = (HashMap) ois.readObject(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java index 5b5104a93..b98cd0e27 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java @@ -607,7 +607,9 @@ public class FrameExporter { final Color fbackgroundColor = backgroundColor; final boolean usesTransparency = settings.mode == FrameExportMode.PNG || settings.mode == FrameExportMode.GIF - || settings.mode == FrameExportMode.WEBP; + || settings.mode == FrameExportMode.WEBP + || settings.mode == FrameExportMode.WEBP_ANIMATED + || settings.mode == FrameExportMode.APNG; final MyFrameIterator frameImages = new MyFrameIterator(tim, fframes, evl, usesTransparency, backgroundColor, settings, subFramesLength); switch (settings.mode) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java index aab7f03ff..5ad599577 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java @@ -56,6 +56,41 @@ import javax.imageio.ImageIO; * @author JPEXS */ public class ImageExporter { + + + private static ImageFormat getExportFormat(ImageTag imageTag, ImageExportSettings settings) { + ImageFormat fileFormat = imageTag.getOriginalImageFormat(); + boolean hasSeparateAlpha = false; + if (imageTag instanceof HasSeparateAlphaChannel) { + HasSeparateAlphaChannel hsac = (HasSeparateAlphaChannel) imageTag; + hasSeparateAlpha = hsac.hasAlphaChannel(); + } + if (settings.mode == ImageExportMode.PNG_GIF_JPEG && hasSeparateAlpha) { + fileFormat = ImageFormat.PNG; + } + if (settings.mode == ImageExportMode.PNG) { + fileFormat = ImageFormat.PNG; + } + + if (settings.mode == ImageExportMode.JPEG) { + fileFormat = ImageFormat.JPEG; + } + + if (settings.mode == ImageExportMode.BMP) { + fileFormat = ImageFormat.BMP; + } + + if (settings.mode == ImageExportMode.WEBP) { + fileFormat = ImageFormat.WEBP; + } + return fileFormat; + } + + public static String getExportExtension(ImageTag imageTag, ImageExportSettings settings) { + ImageFormat fileFormat = getExportFormat(imageTag, settings); + + return ImageHelper.getImageFormatString(fileFormat); + } public List exportImages(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, ImageExportSettings settings, EventListener evl) throws IOException, InterruptedException { List ret = new ArrayList<>(); @@ -90,31 +125,9 @@ public class ImageExporter { final ImageTag imageTag = (ImageTag) t; - ImageFormat fileFormat = imageTag.getOriginalImageFormat(); - ImageFormat originalFormat = fileFormat; - boolean hasSeparateAlpha = false; - if (imageTag instanceof HasSeparateAlphaChannel) { - HasSeparateAlphaChannel hsac = (HasSeparateAlphaChannel) imageTag; - hasSeparateAlpha = hsac.hasAlphaChannel(); - } - if (settings.mode == ImageExportMode.PNG_GIF_JPEG && hasSeparateAlpha) { - fileFormat = ImageFormat.PNG; - } - if (settings.mode == ImageExportMode.PNG) { - fileFormat = ImageFormat.PNG; - } - - if (settings.mode == ImageExportMode.JPEG) { - fileFormat = ImageFormat.JPEG; - } - - if (settings.mode == ImageExportMode.BMP) { - fileFormat = ImageFormat.BMP; - } - - if (settings.mode == ImageExportMode.WEBP) { - fileFormat = ImageFormat.WEBP; - } + + ImageFormat originalFormat = imageTag.getOriginalImageFormat(); + ImageFormat fileFormat = getExportFormat(imageTag, settings); final File file = new File(outdir + File.separator + Helper.makeFileName(imageTag.getCharacterExportFileName() + "." + ImageHelper.getImageFormatString(fileFormat))); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java index 9f0f615b7..f12d9656b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java @@ -188,7 +188,7 @@ public class MorphShapeExporter { } m = Matrix.getScaleInstance(settings.zoom); m.translate(-rect.Xmin, -rect.Ymin); - st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, m, m, m, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, settings.aaScale); + st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, new Matrix(), m, m, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, settings.aaScale); BufferedImage bim = img.getBufferedImage(); if (settings.mode == MorphShapeExportMode.PNG_START_END) { @@ -222,7 +222,7 @@ public class MorphShapeExporter { } m = Matrix.getScaleInstance(settings.zoom); m.translate(-rect.Xmin, -rect.Ymin); - st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, m, m, m, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, settings.aaScale); + st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, new Matrix(), m, m, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, settings.aaScale); bim = img.getBufferedImage(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java index df10574f5..5608504c1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java @@ -149,7 +149,7 @@ public class ShapeExporter { Matrix m2 = Matrix.getScaleInstance(settings.zoom); m2.translate(-rect.Xmin, -rect.Ymin); - st.toImage(0, 0, 0, new RenderContext(), img, img, false, m2, m2, m2, m2, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, aaScale); + st.toImage(0, 0, 0, new RenderContext(), img, img, false, m2, new Matrix(), m2, m2, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true, aaScale); BufferedImage bim = img.getBufferedImage(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java index 2ca02c1d8..cb81c81b8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java @@ -64,6 +64,27 @@ import java.util.Set; */ public class SoundExporter { + public static String getExportExtension(SoundTag soundTag, SoundExportSettings settings) { + String ext = "wav"; + SoundFormat fmt = soundTag.getSoundFormat(); + switch (fmt.getNativeExportFormat()) { + case MP3: + if (settings.mode.hasMP3()) { + ext = "mp3"; + } + break; + case FLV: + if (settings.mode.hasFlv()) { + ext = "flv"; + } + break; + } + if (settings.mode == SoundExportMode.FLV) { + ext = "flv"; + } + return ext; + } + public List exportSounds(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, final SoundExportSettings settings, EventListener evl) throws IOException, InterruptedException { List sounds = new ArrayList<>(); for (Tag t : tags) { @@ -72,7 +93,7 @@ public class SoundExporter { } } return exportSounds(handler, outdir, sounds, settings, evl); - } + } public List exportSounds(AbortRetryIgnoreHandler handler, String outdir, List tags, final SoundExportSettings settings, EventListener evl) throws IOException, InterruptedException { List ret = new ArrayList<>(); @@ -97,24 +118,7 @@ public class SoundExporter { evl.handleExportingEvent("sound", currentIndex, tags.size(), st.getName()); } - String ext = ".wav"; - SoundFormat fmt = st.getSoundFormat(); - switch (fmt.getNativeExportFormat()) { - case MP3: - if (settings.mode.hasMP3()) { - ext = ".mp3"; - } - break; - case FLV: - if (settings.mode.hasFlv()) { - ext = ".flv"; - } - break; - } - if (settings.mode == SoundExportMode.FLV) { - ext = ".flv"; - } - + String ext = "." + getExportExtension(st, settings); final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName()) + ext); new RetryTask(() -> { try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/XamlExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/XamlExporter.java index 5dd3f75bf..4033c3fad 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/XamlExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/XamlExporter.java @@ -402,7 +402,7 @@ public class XamlExporter { int fontId = defineEditText.fontId; FontTag font = null; if (fontId == -1) { - if (defineEditText.fontClass != null) { + if (defineEditText.hasFontClass) { font = swf.getFontByClass(defineEditText.fontClass); fontId = swf.getCharacterId(font); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/XmlSwfExportSettings.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/XmlSwfExportSettings.java new file mode 100644 index 000000000..18368276c --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/XmlSwfExportSettings.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010-2026 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.settings; + +import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode; + +/** + * + * @author JPEXS + */ +public class XmlSwfExportSettings { + public ScriptExportMode as12ExportMode; + public ImageExportMode imageExportMode; + public SoundExportMode defineSoundExportMode; + + public XmlSwfExportSettings() { + } + + public XmlSwfExportSettings(ScriptExportMode as12ExportMode, ImageExportMode imageExportMode, SoundExportMode defineSoundExportMode) { + if (as12ExportMode != null && as12ExportMode != ScriptExportMode.AS) { + throw new IllegalArgumentException("Unsupported script export mode"); + } + this.as12ExportMode = as12ExportMode; + if ( + imageExportMode != null + && imageExportMode != ImageExportMode.PNG_GIF_JPEG + && imageExportMode != ImageExportMode.PNG_GIF_JPEG_ALPHA + ) { + throw new IllegalArgumentException("Unsupported image export mode"); + } + this.imageExportMode = imageExportMode; + if (defineSoundExportMode != null && defineSoundExportMode != SoundExportMode.MP3_WAV_FLV) { + throw new IllegalArgumentException("Unsupported sound export mode"); + } + this.defineSoundExportMode = defineSoundExportMode; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/aa/AntialiasTools.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/aa/AntialiasTools.java index 6fe219138..6aa923160 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/aa/AntialiasTools.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/aa/AntialiasTools.java @@ -154,11 +154,11 @@ public class AntialiasTools { for (int i = 1; i < iPts.length; i++) { path.lineTo(iPts[i].x / (float) FIXED_ONE, iPts[i].y / (float) FIXED_ONE); - } - - if (close) { - path.closePath(); - } + } + } + + if (close) { + path.closePath(); } return path; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/aa/AntialiasedBitmapExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/aa/AntialiasedBitmapExporter.java index c9c4177d9..b41fd555f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/aa/AntialiasedBitmapExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/aa/AntialiasedBitmapExporter.java @@ -204,6 +204,7 @@ public class AntialiasedBitmapExporter extends BitmapExporter { * * @return Image */ + @Override public SerializableImage getImage() { return image; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfXmlExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfXmlExporter.java index e012fc1a3..c74470d80 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfXmlExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfXmlExporter.java @@ -16,13 +16,35 @@ */ package com.jpexs.decompiler.flash.exporters.swf; +import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.ApplicationInfo; +import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.exporters.ImageExporter; +import com.jpexs.decompiler.flash.exporters.SoundExporter; +import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.exporters.script.AS2ScriptExporter; +import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.XmlSwfExportSettings; import com.jpexs.decompiler.flash.helpers.InternalClass; import com.jpexs.decompiler.flash.helpers.LazyObject; +import com.jpexs.decompiler.flash.tags.DefineButtonTag; +import com.jpexs.decompiler.flash.tags.DefineSoundTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.UnknownTag; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.tags.base.ButtonAction; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.SoundTag; +import com.jpexs.decompiler.flash.types.annotations.Conditional; import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.parser.AnnotationParseException; +import com.jpexs.decompiler.flash.types.annotations.parser.ConditionEvaluator; import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.Helper; import com.jpexs.helpers.ReflectionTools; @@ -36,9 +58,14 @@ import java.io.Writer; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.stream.XMLOutputFactory; @@ -58,10 +85,14 @@ public class SwfXmlExporter { */ public static final int XML_EXPORT_VERSION_MAJOR = 2; + public static final int XML_EXPORT_VERSION_MAJOR_WITH_EXTERNAL_FILES = 3; + /** * XML export version minor. + * + * Version 2 - export only fields that meet conditions */ - public static final int XML_EXPORT_VERSION_MINOR = 1; + public static final int XML_EXPORT_VERSION_MINOR = 2; private static final Logger logger = Logger.getLogger(SwfXmlExporter.class.getName()); @@ -75,16 +106,100 @@ public class SwfXmlExporter { * @throws IOException On I/O error */ public void exportXml(SWF swf, File outFile) throws IOException { + exportXml(swf, outFile, new XmlSwfExportSettings(), null, new AbortRetryIgnoreHandler() { + @Override + public int handle(Throwable thrown) { + return AbortRetryIgnoreHandler.ABORT; + } + + @Override + public AbortRetryIgnoreHandler getNewInstance() { + return this; + } + }); + } + + /** + * Exports SWF to XML. + * + * @param swf SWF to export + * @param outFile Target file to save to + * @param settings Export settings + * @param evl Event listener + * @param handler Abort/Retry/Ignore handler + * + * @throws IOException On I/O error + */ + public void exportXml(SWF swf, File outFile, XmlSwfExportSettings settings, EventListener evl, AbortRetryIgnoreHandler handler) throws IOException { try { File tmp = File.createTempFile("FFDEC", "XML"); + String assetsDirName = outFile.getName(); + if (assetsDirName.contains(".")) { + assetsDirName = assetsDirName.substring(0, assetsDirName.lastIndexOf(".")); + } + assetsDirName = assetsDirName + "_assets"; + + Map asmExternalFiles = new HashMap<>(); + if (settings.as12ExportMode != null) { + Map externalNameToAsm = swf.getASMs(true); + Set existingNames = new HashSet<>(); + for (String key : externalNameToAsm.keySet()) { + ASMSource asm = externalNameToAsm.get(key); + String currentOutDir = key + "/"; + currentOutDir = new File(currentOutDir).getParentFile().toString(); + currentOutDir = currentOutDir.replace("\\", "/"); + if (!"/".equals(currentOutDir)) { + currentOutDir += "/"; + } + String name = Helper.makeFileName(asm.getExportFileName()); + int i = 1; + String baseName = name; + while (existingNames.contains(currentOutDir + name)) { + i++; + name = baseName + "_" + i; + } + existingNames.add(currentOutDir + name); + asmExternalFiles.put(asm, assetsDirName + "/scripts" + currentOutDir + name + ".as"); + } + } + + Map tagExternalFiles = new IdentityHashMap<>(); + List imagesList = new ArrayList<>(); + if (settings.imageExportMode != null) { + ImageExportSettings imageExportSetttings = new ImageExportSettings(settings.imageExportMode); + Map chars = swf.getCharacters(false); + for (int charId : chars.keySet()) { + CharacterTag ch = chars.get(charId); + if (ch instanceof ImageTag) { + ImageTag imageTag = (ImageTag) ch; + tagExternalFiles.put(imageTag, assetsDirName + "/images/" + Helper.makeFileName(imageTag.getCharacterExportFileName()) + "." + ImageExporter.getExportExtension(imageTag, imageExportSetttings)); + imagesList.add(imageTag); + } + } + } + + List soundList = new ArrayList<>(); + if (settings.defineSoundExportMode != null) { + SoundExportSettings soundExportSetttings = new SoundExportSettings(settings.defineSoundExportMode); + Map chars = swf.getCharacters(false); + for (int charId : chars.keySet()) { + CharacterTag ch = chars.get(charId); + if (ch instanceof DefineSoundTag) { + DefineSoundTag soundTag = (DefineSoundTag) ch; + tagExternalFiles.put(soundTag, assetsDirName + "/sounds/" + Helper.makeFileName(soundTag.getCharacterExportFileName()) + "." + SoundExporter.getExportExtension(soundTag, soundExportSetttings)); + soundList.add(soundTag); + } + } + } + try (Writer writer = new Utf8OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(tmp)))) { XMLStreamWriter xmlWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(writer); xmlWriter.writeStartDocument(); xmlWriter.writeComment("\r\nWARNING: The structure of this XML is not final.\r\nIn later versions of FFDec it can be changed.\r\nMake sure you use compatible reader/writer based on _xmlExportMajor/_xmlExportMinor keys.\r\n"); - exportXml(swf, xmlWriter); + exportXml(asmExternalFiles, tagExternalFiles, swf, xmlWriter); xmlWriter.writeEndDocument(); xmlWriter.flush(); @@ -100,6 +215,27 @@ public class SwfXmlExporter { logger.log(Level.SEVERE, "Cannot prettyformat XML"); } tmp.delete(); + + if (settings.as12ExportMode != null) { + AS2ScriptExporter exporter = new AS2ScriptExporter(); + exporter.exportActionScript2(swf, handler, outFile.getParentFile().toPath().resolve(assetsDirName + "/scripts").toFile().getAbsolutePath(), new ScriptExportSettings(settings.as12ExportMode, false, false, false, false), true, evl); + } + if (settings.imageExportMode != null) { + ImageExporter exporter = new ImageExporter(); + try { + exporter.exportImages(handler, outFile.getParentFile().toPath().resolve(assetsDirName + "/images").toFile().getAbsolutePath(), new ReadOnlyTagList(imagesList), new ImageExportSettings(settings.imageExportMode), evl); + } catch (InterruptedException ex) { + return; + } + } + if (settings.defineSoundExportMode != null) { + SoundExporter exporter = new SoundExporter(); + try { + exporter.exportSounds(handler, outFile.getParentFile().toPath().resolve(assetsDirName + "/sounds").toFile().getAbsolutePath(), soundList, new SoundExportSettings(settings.defineSoundExportMode), evl); + } catch (InterruptedException ex) { + return; + } + } } catch (XMLStreamException ex) { logger.log(Level.SEVERE, null, ex); } @@ -108,13 +244,30 @@ public class SwfXmlExporter { /** * Exports SWF to XML. * + * @param asmExternalFiles ASM external files + * @param tagExternalFiles Tag external files * @param swf SWF to export * @param writer XML writer * @throws IOException On I/O error * @throws XMLStreamException On XML error */ - public void exportXml(SWF swf, XMLStreamWriter writer) throws IOException, XMLStreamException { - generateXml(writer, "swf", swf, false); + private void exportXml( + Map asmExternalFiles, + Map tagExternalFiles, + SWF swf, + XMLStreamWriter writer + ) throws IOException, XMLStreamException { + generateXml( + asmExternalFiles.isEmpty() && tagExternalFiles.isEmpty() ? XML_EXPORT_VERSION_MAJOR : XML_EXPORT_VERSION_MAJOR_WITH_EXTERNAL_FILES, + asmExternalFiles, + tagExternalFiles, + swf, + null, + writer, + "swf", + swf, + false + ); } public List getSwfFieldsCached(Class cls) { @@ -167,7 +320,17 @@ public class SwfXmlExporter { return cls != null && (cls.isArray() || List.class.isAssignableFrom(cls)); } - private void generateXml(XMLStreamWriter writer, String name, Object obj, boolean isListItem) throws XMLStreamException { + private void generateXml( + int major, + Map asmExternalFiles, + Map tagExternalFiles, + SWF swf, + Tag currentTag, + XMLStreamWriter writer, + String name, + Object obj, + boolean isListItem + ) throws XMLStreamException { Class cls = obj != null ? obj.getClass() : null; /*if (obj != null && cls == String.class) { @@ -215,7 +378,7 @@ public class SwfXmlExporter { writer.writeStartElement(name); int length = Array.getLength(value); for (int i = 0; i < length; i++) { - generateXml(writer, "item", Array.get(value, i), true); + generateXml(major, asmExternalFiles, tagExternalFiles, swf, currentTag, writer, "item", Array.get(value, i), true); } writer.writeEndElement(); } else if (obj != null) { @@ -233,9 +396,10 @@ public class SwfXmlExporter { writer.writeStartElement(name); if (obj instanceof SWF) { - writer.writeAttribute("_xmlExportMajor", "" + XML_EXPORT_VERSION_MAJOR); + writer.writeAttribute("_xmlExportMajor", "" + major); writer.writeAttribute("_xmlExportMinor", "" + XML_EXPORT_VERSION_MINOR); writer.writeAttribute("_generator", ApplicationInfo.applicationVerName); + swf = (SWF) obj; } writer.writeAttribute("type", clazz.getSimpleName()); @@ -247,12 +411,80 @@ public class SwfXmlExporter { writer.writeAttribute("charset", ((SWF) obj).getCharset()); } + boolean isExternal = false; + + if (obj instanceof Tag) { + currentTag = (Tag) obj; + + if (tagExternalFiles.containsKey((Tag) obj)) { + writer.writeAttribute("_externalFile", tagExternalFiles.get((Tag) obj)); + isExternal = true; + } + } + for (Field f : fields) { - //Multiline multilineA = f.getAnnotation(Multiline.class); + //Multiline multilineA = f.getAnnotation(Multiline.class); + + if (isExternal && !"characterID".equals(f.getName()) && !"soundId".equals(f.getName())) { + continue; + } + + Conditional cond = f.getAnnotation(Conditional.class); + if (cond != null) { + ConditionEvaluator ev = new ConditionEvaluator(cond); + try { + Set condFields = ev.getFields(); + Map fieldMap = new HashMap<>(); + for (String sf : condFields) { + try { + Object value = ReflectionTools.getValue(obj, clazz.getField(sf)); + if (value instanceof Boolean) { + fieldMap.put(sf, (Boolean) value); + } + if (value instanceof Integer) { + int intValue = (Integer) value; + boolean found = false; + for (int i : cond.options()) { + if (i == intValue) { + found = true; + } + } + fieldMap.put(sf, found); + } + } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException ex) { + fieldMap.put(sf, true); + } + } + if (!ev.eval(fieldMap, currentTag.getId())) { + continue; + } + } catch (AnnotationParseException ex) { + logger.log(Level.SEVERE, null, ex); + } + } try { f.setAccessible(true); - generateXml(writer, f.getName(), f.get(obj), false); + Object value = f.get(obj); + + if ("actionBytes".equals(f.getName())) { + if (obj instanceof ASMSource && asmExternalFiles.containsKey((ASMSource) obj)) { + value = new ByteArrayRange("00"); + writer.writeAttribute("_externalActions", asmExternalFiles.get((ASMSource) obj)); + } else if (obj instanceof DefineButtonTag) { + for (ASMSource s : asmExternalFiles.keySet()) { + if (s instanceof ButtonAction) { + ButtonAction ba = (ButtonAction) s; + if (ba.getSourceTag() == obj) { + value = new ByteArrayRange("00"); + writer.writeAttribute("_externalActions", asmExternalFiles.get(s)); + break; + } + } + } + } + } + generateXml(major, asmExternalFiles, tagExternalFiles, swf, currentTag, writer, f.getName(), value, false); } catch (IllegalArgumentException | IllegalAccessException ex) { logger.log(Level.SEVERE, null, ex); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/AS2ScriptImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/AS2ScriptImporter.java index 36d28c954..abfa9925e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/AS2ScriptImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/AS2ScriptImporter.java @@ -44,7 +44,6 @@ public class AS2ScriptImporter { private static final Logger logger = Logger.getLogger(AS2ScriptImporter.class.getName()); - /** * Constructor. */ @@ -52,8 +51,58 @@ public class AS2ScriptImporter { } + /** + * Imports actionScript 1/2 (not P-code) from given file + * + * @param fileName File to import + * @param asm Target to import into + * @param listener Import listener + * @return True on success + * @throws InterruptedException + */ + public boolean importActionScript(String fileName, ASMSource asm, ScriptImporterProgressListener listener) throws InterruptedException { + asm.getSwf().informListeners("importing_as", fileName); + String txt = Helper.readTextFile(fileName); + + ActionScript2Parser par = new ActionScript2Parser(asm.getSwf(), asm); + boolean errored = false; + try { + asm.setActions(par.actionsFromString(txt, asm.getSwf().getCharset())); + } catch (ValueTooLargeException ex) { + logger.log(Level.SEVERE, "Script or some of its functions are too large, file: {0}", fileName); + errored = true; + } catch (ActionParseException ex) { + logger.log(Level.SEVERE, "%error% on line %line%, file: %file%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line)).replace("%file%", fileName), ex); + errored = true; + } catch (CompilationException ex) { + logger.log(Level.SEVERE, "%error% on line %line%, file: %file%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line)).replace("%file%", fileName), ex); + errored = true; + } catch (IOException ex) { + logger.log(Level.SEVERE, "error during script import, file: %file%".replace("%file%", fileName), ex); + errored = true; + } catch (InterruptedException ex) { + throw ex; + } catch (Exception ex) { + logger.log(Level.SEVERE, "error during script import, file: %file%".replace("%file%", fileName), ex); + errored = true; + } + + if (!errored) { + asm.setModified(); + if (listener != null) { + listener.scriptImported(); + } + } else { + if (listener != null) { + listener.scriptImportError(); + } + } + return !errored; + } + /** * Imports scripts from given folder. + * * @param scriptsFolder Folder with scripts * @param asms Map of ASMSource objects * @return Number of imported scripts @@ -65,6 +114,7 @@ public class AS2ScriptImporter { /** * Imports scripts from given folder. + * * @param scriptsFolder Folder with scripts * @param asms Map of ASMSource objects * @param listener Progress listener @@ -104,42 +154,12 @@ public class AS2ScriptImporter { String fileName = Path.combine(currentOutDir, name) + ".as"; if (new File(fileName).exists()) { - asm.getSwf().informListeners("importing_as", fileName); - String txt = Helper.readTextFile(fileName); - - ActionScript2Parser par = new ActionScript2Parser(asm.getSwf(), asm); - boolean errored = false; try { - asm.setActions(par.actionsFromString(txt, asm.getSwf().getCharset())); - } catch (ValueTooLargeException ex) { - logger.log(Level.SEVERE, "Script or some of its functions are too large, file: {0}", fileName); - errored = true; - } catch (ActionParseException ex) { - logger.log(Level.SEVERE, "%error% on line %line%, file: %file%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line)).replace("%file%", fileName), ex); - errored = true; - } catch (CompilationException ex) { - logger.log(Level.SEVERE, "%error% on line %line%, file: %file%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line)).replace("%file%", fileName), ex); - errored = true; - } catch (IOException ex) { - logger.log(Level.SEVERE, "error during script import, file: %file%".replace("%file%", fileName), ex); - errored = true; + if (importActionScript(fileName, asm, listener)) { + importCount++; + } } catch (InterruptedException ex) { return importCount; - } catch (Exception ex) { - logger.log(Level.SEVERE, "error during script import, file: %file%".replace("%file%", fileName), ex); - errored = true; - } - - if (!errored) { - asm.setModified(); - importCount++; - if (listener != null) { - listener.scriptImported(); - } - } else { - if (listener != null) { - listener.scriptImportError(); - } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java index aff1ad0ae..28ec39e52 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java @@ -37,11 +37,17 @@ 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.amf.amf3.Amf3Value; +import com.jpexs.decompiler.flash.exporters.swf.SwfXmlExporter; import com.jpexs.decompiler.flash.tags.CSMSettingsTag; +import com.jpexs.decompiler.flash.tags.DefineButtonTag; +import com.jpexs.decompiler.flash.tags.DefineSoundTag; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.TagTypeInfo; import com.jpexs.decompiler.flash.tags.UnknownTag; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.SoundImportException; import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA; import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA; import com.jpexs.decompiler.flash.types.ARGB; @@ -108,12 +114,16 @@ import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; 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.decompiler.flash.types.sound.SoundFormat; import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.HashArrayList; import com.jpexs.helpers.Helper; +import com.jpexs.helpers.IdentityKey; import com.jpexs.helpers.ReflectionTools; import com.jpexs.helpers.utf8.Utf8InputStreamReader; import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; @@ -124,7 +134,9 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -145,7 +157,12 @@ public class SwfXmlImporter { /** * Maximum XML import version major. */ - public static final int MAX_XML_IMPORT_VERSION_MAJOR = 2; + public static final int MAX_XML_IMPORT_VERSION_MAJOR = 3; + + /** + * Minimum version for using external files - attributes _externalActions, _externalFile + */ + public static final int XML_IMPORT_VERSION_MAJOR_WITH_EXTERNAL_FILES = 3; private static final Logger logger = Logger.getLogger(SwfXmlImporter.class.getName()); @@ -221,11 +238,15 @@ public class SwfXmlImporter { * Imports SWF from input stream. * @param swf SWF object * @param in Input stream + * @param directory Directory where XML resides for external files resolving * @throws IOException On I/O error */ - public void importSwf(SWF swf, InputStream in) throws IOException { + public void importSwf(SWF swf, InputStream in, File directory) throws IOException { XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); + Map, String> asmExternalActions = new LinkedHashMap<>(); + Map, String> tagExternalFiles = new LinkedHashMap<>(); + try { try (Reader reader = new Utf8InputStreamReader(new BufferedInputStream(in))) { XMLStreamReader xmlReader = xmlFactory.createXMLStreamReader(reader); @@ -233,7 +254,7 @@ public class SwfXmlImporter { xmlReader.nextTag(); xmlReader.require(XMLStreamConstants.START_ELEMENT, null, "swf"); - processElement(xmlReader, swf, swf, null, MAX_XML_IMPORT_VERSION_MAJOR); + processElement(xmlReader, swf, swf, null, MAX_XML_IMPORT_VERSION_MAJOR, asmExternalActions, tagExternalFiles); } swf.clearAllCache(); @@ -241,16 +262,78 @@ public class SwfXmlImporter { } catch (XMLStreamException ex) { logger.log(Level.SEVERE, null, ex); } + + if (!asmExternalActions.isEmpty()) { + for (IdentityKey objKey : asmExternalActions.keySet()) { + ASMSource asm = null; + String fileName = asmExternalActions.get(objKey); + Object obj = objKey.get(); + if (obj instanceof ASMSource) { + asm = (ASMSource) obj; + } + if (obj instanceof DefineButtonTag) { + DefineButtonTag defineButton = (DefineButtonTag) obj; + asm = defineButton.getSubItems().get(0); + } + if (asm != null) { + AS2ScriptImporter importer = new AS2ScriptImporter(); + try { + importer.importActionScript(directory.toPath().resolve(fileName).toFile().getAbsolutePath(), asm, null); + } catch (InterruptedException ex) { + break; + } + } + } + } + if (!tagExternalFiles.isEmpty()) { + for (IdentityKey tagKey : tagExternalFiles.keySet()) { + String fileName = tagExternalFiles.get(tagKey); + Tag tag = tagKey.get(); + if (tag == null) { + continue; + } + if (tag instanceof ImageTag) { + ImageTag imageTag = (ImageTag) tag; + ImageImporter importer = new ImageImporter(); + importer.importImage(imageTag, Helper.readFile(directory.toPath().resolve(fileName).toFile().getAbsolutePath()), -1); + String baseName = new File(fileName).getName(); + if (baseName.contains(".")) { + baseName = baseName.substring(0, baseName.lastIndexOf(".")); + } + String alphaFile = new File(fileName).getParentFile().getAbsolutePath() + "/" + baseName + ".alpha.png"; + + if (new File(alphaFile).exists()) { + importer.importImageAlpha(imageTag, Helper.readFile(alphaFile)); + } + } else if (tag instanceof DefineSoundTag) { + DefineSoundTag defineSoundTag = (DefineSoundTag) tag; + SoundImporter importer = new SoundImporter(); + int format = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN; + if (fileName.toLowerCase(Locale.ENGLISH).endsWith(".mp3")) { + format = SoundFormat.FORMAT_MP3; + } + try (FileInputStream fis = new FileInputStream(directory.toPath().resolve(fileName).toFile().getAbsolutePath())) { + importer.importDefineSound(defineSoundTag, fis, format); + } catch (SoundImportException ex) { + logger.log(Level.SEVERE, "Cannot import sound", ex); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Cannot read sound", ex); + } + } else { + logger.log(Level.WARNING, "Unrecognized tag type for external file: {0}", tag.getTagName()); + } + } + } } private void setSwfAndTimelined(SWF swf) { for (Tag t : swf.getTags()) { - t.setSwf(swf); + t.setSwf(swf, true); t.setTimelined(swf); if (t instanceof DefineSpriteTag) { DefineSpriteTag s = (DefineSpriteTag) t; for (Tag st : s.getTags()) { - st.setSwf(swf); + st.setSwf(swf, true); st.setTimelined(s); } } @@ -269,7 +352,7 @@ public class SwfXmlImporter { XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); try { XMLStreamReader reader = xmlFactory.createXMLStreamReader(new StringReader(xml)); - return processObject(reader, requiredType, swf, null, 1); + return processObject(reader, requiredType, swf, null, 1, new HashMap<>(), new HashMap<>()); } catch (IllegalArgumentException | IllegalAccessException | NoSuchMethodException | InstantiationException | InvocationTargetException | XMLStreamException ex) { Logger.getLogger(SwfXmlImporter.class.getName()).log(Level.SEVERE, null, ex); @@ -311,7 +394,7 @@ public class SwfXmlImporter { }*/ } - private void processElement(XMLStreamReader reader, Object obj, SWF swf, Tag tag, int xmlExportMajor) throws XMLStreamException { + private void processElement(XMLStreamReader reader, Object obj, SWF swf, Tag tag, int xmlExportMajor, Map, String> asmExternalActions, Map, String> tagExternalFiles) throws XMLStreamException { // Check if element started and start if needed if (!reader.isStartElement()) { reader.nextTag(); @@ -369,6 +452,30 @@ public class SwfXmlImporter { if (name.equals("reserved3") && "FileAttributesTag".equals(attributes.get("type"))) { name = "reservedB"; } + + if (name.equals("_externalActions")) { + if (xmlExportMajor < XML_IMPORT_VERSION_MAJOR_WITH_EXTERNAL_FILES) { + logger.log(Level.WARNING, "For _externalActions attribute _xmlExportMajor must be >= 3. The attribute is ignored."); + continue; + } + asmExternalActions.put(new IdentityKey<>(obj), val); + continue; + } + + if (obj instanceof Tag && name.equals("_externalFile")) { + if (xmlExportMajor < XML_IMPORT_VERSION_MAJOR_WITH_EXTERNAL_FILES) { + logger.log(Level.WARNING, "For _externalFile attribute _xmlExportMajor must be >= 3. The attribute is ignored."); + continue; + } + tagExternalFiles.put(new IdentityKey<>((Tag) obj), val); + continue; + } + + if (name.equals("actionBytes") && attributes.containsKey("_externalActions")) { + if (xmlExportMajor >= XML_IMPORT_VERSION_MAJOR_WITH_EXTERNAL_FILES) { + continue; + } + } if (!name.equals("type")) { try { @@ -397,7 +504,7 @@ public class SwfXmlImporter { // Check for list item elements reader.nextTag(); while (reader.isStartElement()) { - Object childObj = processObject(reader, reqType, swf, tag, xmlExportMajor); + Object childObj = processObject(reader, reqType, swf, tag, xmlExportMajor, asmExternalActions, tagExternalFiles); list.add(childObj); reader.nextTag(); @@ -414,7 +521,7 @@ public class SwfXmlImporter { setFieldValue(field, obj, value); } else { - Object childObj = processObject(reader, null, swf, tag, xmlExportMajor); + Object childObj = processObject(reader, null, swf, tag, xmlExportMajor, asmExternalActions, tagExternalFiles); setFieldValue(field, obj, childObj); } } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException @@ -432,7 +539,7 @@ public class SwfXmlImporter { } } - private Object processObject(XMLStreamReader reader, Class requiredType, SWF swf, Tag tag, int xmlExportMajor) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException, XMLStreamException { + private Object processObject(XMLStreamReader reader, Class requiredType, SWF swf, Tag tag, int xmlExportMajor, Map, String> asmExternalActions, Map, String> tagExternalFiles) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException, XMLStreamException { // Check if element started and start if needed if (!reader.isStartElement()) { reader.nextTag(); @@ -465,7 +572,7 @@ public class SwfXmlImporter { tag = (Tag) childObj; } - processElement(reader, childObj, swf, tag, xmlExportMajor); + processElement(reader, childObj, swf, tag, xmlExportMajor, asmExternalActions, tagExternalFiles); ret = childObj; } else { String isNullAttr = attributes.get("isNull"); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources_tr.properties b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources_tr.properties index 9cabc45d6..cfadbdb25 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources_tr.properties +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources_tr.properties @@ -63,3 +63,6 @@ configurationFile.configuration = B\u00f6l\u00fcm - Ger\u00e7ek yap\u0131land\u0 configuration.removed = UYARI: Bu yap\u0131land\u0131rma KALDIRILDI. Kullan\u0131lm\u0131yor. #after 24.0.1 decompilationWarning.as2.noUninitializedClassFieldsDetection = UYARI: Bu s\u0131n\u0131f, ba\u015flat\u0131lmam\u0131\u015f s\u0131n\u0131f alanlar\u0131 alg\u0131lanmadan derlendi. +decompilationWarning.obfuscatedIdentifiers = UYARI: Orijinal kodda gizlenmi\u015f tan\u0131mlay\u0131c\u0131lar bulunmaktad\u0131r. +decompilationWarning.replacementsFollow = De\u011fi\u015ftirilen \u00f6\u011felerin listesi a\u015fa\u011f\u0131dad\u0131r: +frame.withoutShowFrame = ShowFrame olmadan diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ABCSearchResult.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ABCSearchResult.java index 3433297d5..ce21ddd6f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ABCSearchResult.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ABCSearchResult.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.flash.treeitems.Openable; import com.jpexs.decompiler.graph.DottedChain; +import com.jpexs.helpers.AllowedObjectInputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; @@ -96,7 +97,7 @@ public class ABCSearchResult implements Serializable, ScriptSearchResult { */ @SuppressWarnings("unchecked") public ABCSearchResult(Openable openable, InputStream is) throws IOException, ScriptNotFoundException { - ObjectInputStream ois = new ObjectInputStream(is); + ObjectInputStream ois = new AllowedObjectInputStream(is); int versionMajor = ois.read(); ois.read(); //minor if (versionMajor == 1) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionSearchResult.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionSearchResult.java index e34f12f16..17097454f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionSearchResult.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionSearchResult.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.search; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.flash.treeitems.Openable; +import com.jpexs.helpers.AllowedObjectInputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; @@ -52,7 +53,7 @@ public class ActionSearchResult implements ScriptSearchResult { */ public ActionSearchResult(SWF swf, InputStream is) throws IOException, ScriptNotFoundException { Map asms = swf.getASMs(false); - ObjectInputStream ois = new ObjectInputStream(is); + ObjectInputStream ois = new AllowedObjectInputStream(is); int versionMajor = ois.read(); ois.read(); //minor if (versionMajor != SERIAL_VERSION_MAJOR) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java index 3632cc78c..4fccf35df 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java @@ -377,4 +377,17 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { needed.add(rec.characterId); } } + + @Override + public void setSwf(SWF swf, boolean deep) { + super.setSwf(swf, deep); + + if (deep) { + if (actions != null) { + for (BUTTONCONDACTION action : actions) { + action.setSourceTag(this); + } + } + } + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java index 9dd1ab720..5a146daa0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java @@ -329,5 +329,5 @@ public class DefineButtonTag extends ButtonTag implements ASMSourceContainer { for (BUTTONRECORD rec : characters) { needed.add(rec.characterId); } - } + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index a9ccad1b9..93a33d08a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -538,7 +538,7 @@ public class DefineEditTextTag extends TextTag { } String str = ""; TextStyle style = new TextStyle(); - if (fontClass != null) { + if (hasFontClass) { style.font = swf.getFontByClass(fontClass); } else { style.font = swf.getFont(fontId); @@ -1355,15 +1355,22 @@ public class DefineEditTextTag extends TextTag { } if (hasText) { List allTextRecords = getTextRecords(swf, normalizedFonts); + + MATRIX textMatrix = new MATRIX(); + + int borderPadding = 40; + textMatrix.translateX = bounds.Xmin + borderPadding; + textMatrix.translateY = bounds.Ymin + borderPadding; + switch (renderMode) { case BITMAP: - staticTextToImage(swf, allTextRecords, 2, image, getTextMatrix(), transformation, colorTransform, selectionStart, selectionEnd, aaScale); + staticTextToImage(swf, allTextRecords, 2, image, textMatrix, transformation, colorTransform, selectionStart, selectionEnd, aaScale); break; case HTML5_CANVAS: - staticTextToHtmlCanvas(zoom, swf, allTextRecords, 2, htmlCanvasBuilder, getBounds(), getTextMatrix(), colorTransform); + staticTextToHtmlCanvas(zoom, swf, allTextRecords, 2, htmlCanvasBuilder, getBounds(), textMatrix, colorTransform); break; case SVG: - staticTextToSVG(swf, allTextRecords, 2, svgExporter, getBounds(), getTextMatrix(), colorTransform, zoom, transformation); + staticTextToSVG(swf, allTextRecords, 2, svgExporter, getBounds(), textMatrix, colorTransform, zoom, transformation); break; } } @@ -1607,8 +1614,8 @@ public class DefineEditTextTag extends TextTag { for (SameStyleTextRecord tr : line) { AdvancedTextRecord tr2 = new AdvancedTextRecord(); int fid = fontId; - if (fontClass != null) { - tr2.fontClass = fontClass; + if (hasFontClass) { + tr2.fontClass = fontClass; //FIXME? } if (tr.style.font != null) { fid = swf.getCharacterId(tr.style.font); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/PlaceObjectTypeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/PlaceObjectTypeTag.java index fd29c97d6..c80886348 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/PlaceObjectTypeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/PlaceObjectTypeTag.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.amf.amf3.Amf3Value; import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD; import com.jpexs.decompiler.flash.types.CLIPACTIONS; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.MATRIX; @@ -361,4 +362,19 @@ public abstract class PlaceObjectTypeTag extends Tag implements CharacterIdTag, result += "_" + getDepth(); return result; } + + @Override + public void setSwf(SWF swf, boolean deep) { + super.setSwf(swf, deep); + + if (deep) { + CLIPACTIONS clipActions = getClipActions(); + if (clipActions != null) { + for (CLIPACTIONRECORD rec : clipActions.clipActionRecords) { + rec.setParentClipActions(clipActions); + rec.setSourceTag(this); + } + } + } + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/converters/TextTypeConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/converters/TextTypeConverter.java index 3c5941cc0..da6cc3052 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/converters/TextTypeConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/converters/TextTypeConverter.java @@ -17,6 +17,7 @@ import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; import com.jpexs.decompiler.flash.types.TEXTRECORD; import com.jpexs.decompiler.flash.xfl.XFLXmlWriter; +import java.awt.Color; import java.io.IOException; import java.util.HashMap; import java.util.List; @@ -99,6 +100,12 @@ public class TextTypeConverter { throw new IllegalArgumentException("defineTextVersion should be either 1 or 2"); } List records = tag.getTextRecords(tag.getSwf(), new HashMap<>()); + + int borderPadding = 40; + int moveX = tag.bounds.Xmin + borderPadding; + int moveY = tag.bounds.Ymin + borderPadding; + + boolean first = true; for (TEXTRECORD rec : records) { if (defineTextVersion == 1 && rec.textColorA != null) { rec.textColor = new RGB(rec.textColorA); @@ -107,8 +114,24 @@ public class TextTypeConverter { if (defineTextVersion == 2 && rec.textColor != null) { rec.textColorA = new RGBA(rec.textColor); rec.textColor = null; - } + } + + if (first) { + rec.styleFlagsHasXOffset = true; + rec.xOffset += moveX; + rec.styleFlagsHasYOffset = true; + rec.yOffset += moveY; + first = false; + } else { + if (rec.styleFlagsHasXOffset) { + rec.xOffset += moveX; + } + if (rec.styleFlagsHasYOffset) { + rec.yOffset += moveY; + } + } } + ret.textRecords = records; ret.textMatrix = new MATRIX(); ExportRectangle bounds = ret.calculateTextBounds(); @@ -132,20 +155,27 @@ public class TextTypeConverter { List leftMargins = (List) attrs.get("allLeftMargins"); @SuppressWarnings("unchecked") List letterSpacings = (List) attrs.get("allLetterSpacings"); - + + int leftMargin = leftMargins.isEmpty() ? 0 : leftMargins.get(0); + det.bounds = new RECT(tag.getBounds()); det.wasStatic = true; det.noSelect = true; det.useOutlines = true; det.multiline = true; + det.hasLayout = true; + det.align = DefineEditTextTag.ALIGN_LEFT; det.indent = (int) attrs.get("indent"); - det.leftMargin = leftMargins.isEmpty() ? 0 : leftMargins.get(0); + det.leftMargin = 0; det.leading = (int) attrs.get("lineSpacing"); det.rightMargin = (int) attrs.get("rightMargin"); XFLXmlWriter writer = new XFLXmlWriter(); writer.setMakeNewLines(false); + RGBA firstTextColor = new RGBA(Color.BLACK); + int firstFontId = -1; + int firstTextHeight = -1; try { int fontId; FontTag font = null; @@ -160,10 +190,16 @@ public class TextTypeConverter { for (int r = 0; r < textRecords.size(); r++) { TEXTRECORD rec = textRecords.get(r); if (rec.styleFlagsHasColor) { + RGBA newTextColor; if (tag instanceof DefineTextTag) { textColor = rec.textColor; + newTextColor = new RGBA(textColor); } else { textColorA = rec.textColorA; + newTextColor = rec.textColorA; + } + if (r == 0) { + firstTextColor = newTextColor; } } if (rec.styleFlagsHasFont) { @@ -182,6 +218,10 @@ public class TextTypeConverter { if (fontName == null) { fontName = FontTag.getDefaultFontName(); } + if (r == 0) { + firstFontId = fontId; + firstTextHeight = textHeight; + } } newline = false; if (!firstRun && rec.styleFlagsHasYOffset) { @@ -190,6 +230,7 @@ public class TextTypeConverter { firstRun = false; if (font != null) { writer.writeStartElement("p"); + writer.writeAttribute("align", "left"); writer.writeStartElement("font"); writer.writeAttribute("face", fontName); writer.writeAttribute("size", doubleToString(twipToPixel(textHeight))); @@ -225,9 +266,16 @@ public class TextTypeConverter { det.html = true; det.hasText = true; det.initialText = writer.toString(); + det.hasTextColor = true; + det.textColor = firstTextColor; + if (firstFontId > -1) { + det.hasFont = true; + det.fontId = firstFontId; + det.fontHeight = firstTextHeight; + } ExportRectangle bounds = det.calculateTextBounds(); - det.bounds = new RECT((int) Math.round(bounds.xMin), (int) Math.round(bounds.xMax), (int) Math.round(bounds.yMin), (int) Math.round(bounds.yMax)); + det.bounds = new RECT((int) Math.round(bounds.xMin + leftMargin), (int) Math.round(bounds.xMax + leftMargin), (int) Math.round(bounds.yMin), (int) Math.round(bounds.yMax)); return det; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS3Package.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS3Package.java index 59cbb6730..58303dfe6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS3Package.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS3Package.java @@ -273,10 +273,15 @@ public class AS3Package extends AS3ClassTreeItem { * * @param script ScriptPack */ - public void addScriptPack(ScriptPack script) { - /*ClassPath cp = script.getClassPath(); - scripts.put(cp.className + cp.namespaceSuffix, script);*/ - scripts.put(script.getPrintableNameWithNamespaceSuffix(), script); + public void addScriptPack(ScriptPack script) { + int i = 1; + String baseKey = script.getPrintableNameWithNamespaceSuffix(); + String key = baseKey; + while (scripts.containsKey(key)) { + i++; + key = baseKey + i; + } + scripts.put(key, script); sortedScripts = null; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONRECORD.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONRECORD.java index 07d73e460..c68173b4a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONRECORD.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONRECORD.java @@ -120,7 +120,7 @@ public class BUTTONRECORD implements Serializable, TreeItem, HasSwfAndTag, HasCh * If within DefineButton2Tag and buttonHasBlendMode: Blend mode */ @SWFType(BasicType.UI8) - @Conditional(value = {"buttonHasBlendMode"}, tags = {DefineButton2Tag.ID}) + @Conditional(value = "buttonHasBlendMode", tags = {DefineButton2Tag.ID}) @EnumValue(value = 0, text = "normal") @EnumValue(value = BlendMode.NORMAL, text = "normal") @EnumValue(value = BlendMode.LAYER, text = "layer") diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/FLAVersion.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/FLAVersion.java index 7f963ac1a..b49e88594 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/FLAVersion.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/FLAVersion.java @@ -24,21 +24,20 @@ import com.jpexs.flash.fla.converter.FlaFormatVersion; * @author JPEXS */ public enum FLAVersion { - F5("F5", "Flash 5", FlaFormatVersion.F5, null, 5), - MX("MX", "Flash MX", FlaFormatVersion.MX, null, 6), - MX2004("MX2004", "Flash MX 2004", FlaFormatVersion.MX2004, null, 7), - F8("F8", "Flash 8", FlaFormatVersion.F8, null, 8), - CS3("CS3", "Flash CS 3", FlaFormatVersion.CS3, null, 9), - CS4("CS4", "Flash CS 4", FlaFormatVersion.CS4, null, 10), - CS5("CS5", "Flash CS 5", null, "2.0", 10), - CS5_5("CS5.5", "Flash CS 5.5", null, "2.1", 11), - CS6("CS6", "Flash CS 6", null, "2.2", 17), - CC("CC", "Flash CC", null, "2.4", Integer.MAX_VALUE) { - @Override - public int minASVersion() { - return 3; //AS 1/2 not supported anymore - } - }; + F1("F1", "FutureSplash Animator", FlaFormatVersion.F1, null, 1, 1, 1), + F2("F2", "Macromedia Flash 2", FlaFormatVersion.F2, null, 2, 1, 1), + F3("F3", "Macromedia Flash 3", FlaFormatVersion.F3, null, 3, 1, 1), + F4("F4", "Macromedia Flash 4", FlaFormatVersion.F4, null, 4, 1, 1), + F5("F5", "Macromedia Flash 5", FlaFormatVersion.F5, null, 5, 1, 1), + MX("MX", "Macromedia Flash MX", FlaFormatVersion.MX, null, 6, 1, 1), + MX2004("MX2004", "Macromedia Flash MX 2004", FlaFormatVersion.MX2004, null, 7, 1, 2), + F8("F8", "Macromedia Flash 8", FlaFormatVersion.F8, null, 8, 1, 2), + CS3("CS3", "Adobe Flash Professional CS 3", FlaFormatVersion.CS3, null, 9, 1, 3), + CS4("CS4", "Adobe Flash Professional CS 4", FlaFormatVersion.CS4, null, 10, 1, 3), + CS5("CS5", "Adobe Flash Professional CS 5", null, "2.0", 10, 1, 3), + CS5_5("CS5.5", "Adobe Flash Professional CS 5.5", null, "2.1", 11, 1, 3), + CS6("CS6", "Adobe Flash Professional CS 6", null, "2.2", 17, 1, 3), + CC("CC", "Adobe Flash Professional CC", null, "2.4", Integer.MAX_VALUE, 3, 3); private final FlaFormatVersion cfbFlaVersion; private final String xflVersion; @@ -48,13 +47,19 @@ public enum FLAVersion { private final String applicationName; private final int maxSwfVersion; + + private final int minASVersion; - private FLAVersion(String shortName, String applicationName, FlaFormatVersion cfbFlaVersion, String xflVersion, int maxSwfVersion) { + private final int maxASVersion; + + private FLAVersion(String shortName, String applicationName, FlaFormatVersion cfbFlaVersion, String xflVersion, int maxSwfVersion, int minASVersion, int maxASVersion) { this.cfbFlaVersion = cfbFlaVersion; this.xflVersion = xflVersion; this.shortName = shortName; this.applicationName = applicationName; this.maxSwfVersion = maxSwfVersion; + this.minASVersion = minASVersion; + this.maxASVersion = maxASVersion; } public FlaFormatVersion getCfbFlaVersion() { @@ -70,7 +75,11 @@ public enum FLAVersion { } public int minASVersion() { - return 1; + return minASVersion; + } + + public int maxASVersion() { + return maxASVersion; } public String applicationName() { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/LosslessImageBinDataReader.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/LosslessImageBinDataReader.java index 76f8c7a6d..3e4ca30b5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/LosslessImageBinDataReader.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/LosslessImageBinDataReader.java @@ -34,6 +34,19 @@ import javax.imageio.ImageIO; */ public class LosslessImageBinDataReader { + /* + Major versions: + + 0 = basic uncompressed, no alpha + 1 = ?? - not encountered + 2 = has compression (variant field) + 3 = adds alpha channel (flags field) + + Minor version: always 5 + + */ + + private final DataInputStream is; public LosslessImageBinDataReader(InputStream is) { @@ -41,9 +54,9 @@ public class LosslessImageBinDataReader { } public BufferedImage readImage() throws IOException { - int sign1 = readEx(); - int sign2 = readEx(); - if (sign1 != 0x03 || sign2 != 0x05) { + int major = readEx(); + int minor = readEx(); + if (major > 3 || minor != 0x05) { throw new IOException("Invalid image"); } int rowSize = readUI16(); @@ -53,29 +66,38 @@ public class LosslessImageBinDataReader { long frameRight = readUI32(); long frameTop = readUI32(); long frameBottom = readUI32(); - int flags = readEx(); - - boolean hasAlpha = (flags & 1) == 1; + + boolean hasAlpha = false; + + if (major >= 3) { + int flags = readEx(); + hasAlpha = (flags & 1) == 1; + } ByteArrayOutputStream baos = new ByteArrayOutputStream(); - int variant = readEx(); - if (variant == 1) { //compressed - while (true) { - int chunkLen = readUI16(); - if (chunkLen == 0) { - break; + + InputStream dis = is; + + if (major >= 2) { + int variant = readEx(); + if (variant == 1) { //compressed + while (true) { + int chunkLen = readUI16(); + if (chunkLen == 0) { + break; + } + byte[] chunk = new byte[chunkLen]; + is.readFully(chunk); + baos.write(chunk); } - byte[] chunk = new byte[chunkLen]; - is.readFully(chunk); - baos.write(chunk); + dis = new InflaterInputStream(new ByteArrayInputStream(baos.toByteArray())); } } ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); - InflaterInputStream iis = new InflaterInputStream(new ByteArrayInputStream(baos.toByteArray())); byte[] buf = new byte[4096]; int cnt; - while ((cnt = iis.read(buf)) > 0) { + while ((cnt = dis.read(buf)) > 0) { baos2.write(buf, 0, cnt); } @@ -96,6 +118,10 @@ public class LosslessImageBinDataReader { g = (int) Math.floor(g * 256f / a); b = (int) Math.floor(b * 256f / a); } + + if (!hasAlpha) { + a = 0xFF; + } int rgba = r + (g << 8) + (b << 16) + (a << 24); img.setRGB(x, y, rgba); @@ -121,9 +147,9 @@ public class LosslessImageBinDataReader { } public static void main(String[] args) throws IOException { - File f = new File("in.bin"); + File f = new File("c:\\Dropbox\\Programovani\\JavaSE\\FlaComDoc\\out\\media\\M 6 1776533974.dat"); LosslessImageBinDataReader r = new LosslessImageBinDataReader(new FileInputStream(f)); BufferedImage i = r.readImage(); - ImageIO.write(i, "PNG", new File("out.png")); + ImageIO.write(i, "PNG", new File("c:\\Dropbox\\Programovani\\JavaSE\\FlaComDoc\\out\\media\\out.png")); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index dc93da4f0..d58b2b841 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -181,7 +181,7 @@ public class Graph { if (heads != null) { return; } - heads = makeGraph(code, new ArrayList<>(), exceptions); + heads = makeGraph(code, new ArrayList<>(), exceptions); } /** @@ -270,16 +270,16 @@ public class Graph { return; } allParts.add(part); - + Queue q = new ArrayDeque<>(); q.offer(part); while (!q.isEmpty()) { - part = q.poll(); + part = q.poll(); for (GraphPart p : part.nextParts) { if (!allParts.contains(p)) { allParts.add(p); q.offer(p); - } + } } } } @@ -2545,7 +2545,7 @@ public class Graph { } for (Loop l : loops) { - if (l.phase == 2) { + if (l.phase != 1) { continue; } if (l.loopContinue == part) { @@ -4086,7 +4086,7 @@ public class Graph { GraphTargetItem pushedValue = pi.value; GraphTargetItem rightSide = ((PushItem) filteredOnTrue.get(filteredOnTrue.size() - 1)).value; GraphTargetItem prevExpr = stack.pop(); - GraphTargetItem leftSide = expr.getNotCoercedNoDup(); + GraphTargetItem leftSide = expr.getNotCoercedNoDup(); GraphTargetItem invertedLeftSide = leftSide; if (invertedLeftSide instanceof NotItem) { invertedLeftSide = ((NotItem) invertedLeftSide).value; @@ -4096,7 +4096,7 @@ public class Graph { prevExpr = prevExpr.getThroughDuplicate(); - boolean hideEmptyTrueFalse = true; + boolean hideEmptyTrueFalse = true; if (leftSide instanceof DuplicateItem || leftSide.getNotCoerced() == prevExpr) { @@ -4205,7 +4205,7 @@ public class Graph { loopStack.push(new LoopLocalData(part, isLoop, loopItem, li, currentLoop, loopTypeFound, doWhileCandidate, precontinueCommands, stopPart, stopPartKind, ret, sPreLoop)); } parent = part; - part = nextOnePart; + part = nextOnePart; nextOnePart = null; isLoop = false; li = null; @@ -4223,7 +4223,7 @@ public class Graph { } break; } - + while (!loopStack.isEmpty()) { LoopLocalData loopLocalData = loopStack.pop(); if (loopLocalData.isLoop && loopLocalData.loopItem != null && loopLocalData.currentLoop != null) { @@ -4624,10 +4624,9 @@ public class Graph { HashMap> refs = code.visitCode(alternateEntries); List gret = new ArrayList<>(); boolean[] visited = new boolean[code.size()]; - + Queue q = new ArrayDeque<>(); - - + //ret.add(makeGraph(null, new GraphPath(), code, startIp, 0, allBlocks, refs, visited)); q.offer(new MakeGraphWindow(null, new GraphPath(), startIp, 0)); for (int pos : alternateEntries) { @@ -4635,14 +4634,14 @@ public class Graph { e1.path = new GraphPath("e"); //ret.add(makeGraph(e1, new GraphPath("e"), code, pos, pos, allBlocks, refs, visited)); q.offer(new MakeGraphWindow(e1, new GraphPath("e"), pos, pos)); - } + } - - loopq: while (!q.isEmpty()) { + loopq: + while (!q.isEmpty()) { if (CancellableWorker.isInterrupted()) { throw new InterruptedException(); } - MakeGraphWindow window = q.poll(); + MakeGraphWindow window = q.poll(); GraphPart parent = window.parent; GraphPath path = window.path; int startIp = window.startIp; @@ -4768,14 +4767,14 @@ public class Graph { part.nextParts.add(gp); allBlocks.add(part); } - } + } } - - gret.add(searchPart(startIp, allBlocks)); + + gret.add(searchPart(startIp, allBlocks)); for (int pos : alternateEntries) { gret.add(searchPart(pos, allBlocks)); } - + if (Configuration.autoDeobfuscate.get()) { flattenJumps(gret, allBlocks); } @@ -4783,8 +4782,8 @@ public class Graph { return gret; } - private class MakeGraphWindow { + GraphPart parent; GraphPath path; int startIp; @@ -4795,10 +4794,9 @@ public class Graph { this.path = path; this.startIp = startIp; this.lastIp = lastIp; - } + } } - - + /** * Converts list of TreeItems to string. * diff --git a/libsrc/ffdec_lib/src/com/jpexs/helpers/AllowedObjectInputStream.java b/libsrc/ffdec_lib/src/com/jpexs/helpers/AllowedObjectInputStream.java new file mode 100644 index 000000000..f0f7d71b0 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/helpers/AllowedObjectInputStream.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010-2026 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.helpers; + +import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration; +import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration; +import com.jpexs.decompiler.flash.configuration.enums.GridSnapAccuracy; +import com.jpexs.decompiler.flash.configuration.enums.GuidesSnapAccuracy; +import com.jpexs.decompiler.flash.exporters.modes.ExeExportMode; +import com.jpexs.decompiler.flash.importers.TextImportResizeTextBoundsMode; +import java.awt.Color; +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.util.Arrays; +import java.util.Calendar; +import java.util.List; + +/** + * ObjectInputStream that limits deserialized classes to safe ones. + * @author JPEXS + */ +public class AllowedObjectInputStream extends ObjectInputStream { + private static final List ALLOWED_CLASSES = Arrays.asList( + "java.lang.String", + "java.lang.Number", + "java.lang.Short", + "java.lang.Long", + "java.lang.Integer", + "java.lang.Double", + "java.lang.Float", + "java.lang.Boolean", + "java.util.ArrayList", + "java.util.LinkedList", + "java.util.HashSet", + "java.util.LinkedHashSet", + "java.util.HashMap", + "java.util.LinkedHashMap", + SwfSpecificConfiguration.class.getName(), + SwfSpecificCustomConfiguration.class.getName(), + ExeExportMode.class.getName(), + TextImportResizeTextBoundsMode.class.getName(), + Color.class.getName(), + GridSnapAccuracy.class.getName(), + GuidesSnapAccuracy.class.getName(), + Calendar.class.getName() + ); + + public AllowedObjectInputStream(InputStream in) throws IOException { + super(in); + } + + @Override + protected Class resolveClass(ObjectStreamClass desc) + throws IOException, ClassNotFoundException { + + String className = desc.getName(); + + if (!ALLOWED_CLASSES.contains(className)) { + throw new InvalidClassException( + "Unauthorized deserialization attempt", className); + } + + return super.resolveClass(desc); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/helpers/IdentityKey.java b/libsrc/ffdec_lib/src/com/jpexs/helpers/IdentityKey.java new file mode 100644 index 000000000..dfb1f0f55 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/helpers/IdentityKey.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010-2026 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.helpers; + +/** + * + * @author JPEXS + */ +public class IdentityKey { + private final T value; + + public IdentityKey(T value) { + this.value = value; + } + + @Override + public int hashCode() { + return System.identityHashCode(value); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof IdentityKey + && ((IdentityKey) obj).value == value; + } + + public T get() { + return value; + } +} \ No newline at end of file diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2AssemblerTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2AssemblerTest.java index 78dccdf2e..824c9b598 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2AssemblerTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2AssemblerTest.java @@ -627,4 +627,23 @@ public class ActionScript2AssemblerTest extends ActionScript2TestBase { assertEquals(res, "c += 1;"); } + @Test + public void testTellTarget() { + String res = decompilePcode("SetTarget \"\"\n" + + "GotoFrame 1\n" + + "SetTarget \"../test\"\n" + + "GoToLabel \"MyLabel\"\n" + + "Play"); + res = cleanPCode(res); + assertEquals(res, "tellTarget(\"\")\n" + + "{\n" + + "gotoAndStop(2);\n" + + "}\n" + + "tellTarget(\"../test\")\n" + + "{\n" + + "gotoAndStop(\"MyLabel\");\n" + + "play();\n" + + "}"); + } + } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/SwfXmlExportImportTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/SwfXmlExportImportTest.java index 52d0cf19c..74ff2bf61 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/SwfXmlExportImportTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/SwfXmlExportImportTest.java @@ -98,7 +98,7 @@ public class SwfXmlExportImportTest extends FileTestBase { SWF swf2 = new SWF(); try ( FileInputStream fis = new FileInputStream(outFile)) { - new SwfXmlImporter().importSwf(swf2, fis); + new SwfXmlImporter().importSwf(swf2, fis, outFile.getParentFile()); } if (swf.getTags().size() != swf2.getTags().size()) { diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicAirDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicAirDecompileTest.java index f7e9863db..81ce3180d 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicAirDecompileTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicAirDecompileTest.java @@ -1834,7 +1834,15 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile + "{\r\n" + "return (param1 as TestClass2).attrib1 == 5;\r\n" + "};\r\n" - + "})();\r\n", + + "})();\r\n" + + "f(5,(function():*\r\n" + + "{\r\n" + + "var g:Function;\r\n" + + "return g = function():int\r\n" + + "{\r\n" + + "return 42;\r\n" + + "};\r\n" + + "})());\r\n", false); } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicDecompileTest.java index 52ac41aca..3eb47d3f4 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicDecompileTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicDecompileTest.java @@ -1831,7 +1831,11 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes decompileMethod("classic", "testNamedAnonFunctions", "var test:* = function testFunc(param1:*, param2:int, param3:Array):Boolean\r\n" + "{\r\n" + "return (param1 as TestClass2).attrib1 == 5;\r\n" - + "};\r\n", + + "};\r\n" + + "this.f(5,function g():int\r\n" + + "{\r\n" + + "return 42;\r\n" + + "});\r\n", false); } diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf index c7c10d4a4..b61f62f03 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf index 1aaa3549f..4b5f60fc9 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestNamedAnonFunctions.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestNamedAnonFunctions.as index 6e7cb644b..b8b570c5d 100644 --- a/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestNamedAnonFunctions.as +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestNamedAnonFunctions.as @@ -8,7 +8,14 @@ package tests { return (param1 as TestClass2).attrib1 == 5; }; - } + f(5, function g():int { + return 42; + }); + } + + private function f(a:int,b:Function) + { + } } } diff --git a/libsrc/ffdec_lib/testexpected/as3_new/tests/TestConvert.as b/libsrc/ffdec_lib/testexpected/as3_new/tests/TestConvert.as index 2b6ef0657..1e178508f 100644 --- a/libsrc/ffdec_lib/testexpected/as3_new/tests/TestConvert.as +++ b/libsrc/ffdec_lib/testexpected/as3_new/tests/TestConvert.as @@ -118,7 +118,7 @@ package tests convert_i setlocal 5 getlocal 5 - coerce_s + convert_s coerce_s setlocal1 getlocal0 @@ -133,7 +133,7 @@ package tests ofs0085: getlocal2 ofs0086: - coerce_s + convert_s coerce_s setlocal1 getlocal2 @@ -143,7 +143,7 @@ package tests jump ofs0098 ofs0096: getlocal2 - coerce_s + convert_s ofs0098: coerce_s setlocal1 @@ -222,19 +222,19 @@ package tests convert_i setlocal2 getlex QName(ProtectedNamespace("tests_classes:TestConvertParent"),"prot") - coerce_s + convert_s coerce_s setlocal1 getlex QName(StaticProtectedNs("tests_classes:TestConvertParent"),"sprot") convert_i setlocal2 getlex QName(StaticProtectedNs("tests_classes:TestConvertParent"),"sprot") - coerce_s + convert_s coerce_s setlocal1 findpropstrict QName(PackageNamespace("flash.utils"),"getTimer") callproperty QName(PackageNamespace("flash.utils"),"getTimer"), 0 - coerce_s + convert_s coerce_s setlocal1 getlex QName(PackageNamespace(""),"XML") @@ -279,7 +279,7 @@ package tests getlocal2 getproperty MultinameL([PackageNamespace(""),Namespace("http://adobe.com/AS3/2006/builtin"),PackageNamespace("tests"),PackageInternalNs("tests"),StaticProtectedNs("tests_classes:TestConvertParent"),PrivateNamespace("tests:TestConvert"),ProtectedNamespace("tests:TestConvert"),StaticProtectedNs("tests:TestConvert"),PrivateNamespace("TestConvert.as$0")]) getproperty MultinameA("id",[PackageNamespace(""),Namespace("http://adobe.com/AS3/2006/builtin"),PackageNamespace("tests"),PackageInternalNs("tests"),StaticProtectedNs("tests_classes:TestConvertParent"),PrivateNamespace("tests:TestConvert"),ProtectedNamespace("tests:TestConvert"),StaticProtectedNs("tests:TestConvert"),PrivateNamespace("TestConvert.as$0")]) - coerce_s + convert_s pushstring "Hello" setproperty MultinameL([PackageNamespace(""),Namespace("http://adobe.com/AS3/2006/builtin"),PackageNamespace("tests"),PackageInternalNs("tests"),StaticProtectedNs("tests_classes:TestConvertParent"),PrivateNamespace("tests:TestConvert"),ProtectedNamespace("tests:TestConvert"),StaticProtectedNs("tests:TestConvert"),PrivateNamespace("TestConvert.as$0")]) findpropstrict QName(PrivateNamespace("TestConvert.as$0"),"LocalClass") @@ -292,7 +292,7 @@ package tests setlocal2 getlocal 10 getproperty Multiname("attr",[PackageNamespace(""),Namespace("http://adobe.com/AS3/2006/builtin"),PackageNamespace("tests"),PackageInternalNs("tests"),StaticProtectedNs("tests_classes:TestConvertParent"),PrivateNamespace("tests:TestConvert"),ProtectedNamespace("tests:TestConvert"),StaticProtectedNs("tests:TestConvert"),PrivateNamespace("TestConvert.as$0")]) - coerce_s + convert_s coerce_s setlocal1 getlocal0 @@ -370,7 +370,7 @@ package tests setlocal2 findpropstrict QName(ProtectedNamespace("tests_classes:TestConvertParent"),"prot") getsuper QName(ProtectedNamespace("tests_classes:TestConvertParent"),"prot") - coerce_s + convert_s coerce_s setlocal1 pushstring "5" diff --git a/libsrc/ffdec_lib/testexpected/as3_new/tests/TestManualConvert.as b/libsrc/ffdec_lib/testexpected/as3_new/tests/TestManualConvert.as index 18b355810..be2f2f303 100644 --- a/libsrc/ffdec_lib/testexpected/as3_new/tests/TestManualConvert.as +++ b/libsrc/ffdec_lib/testexpected/as3_new/tests/TestManualConvert.as @@ -66,7 +66,7 @@ package tests callpropvoid Multiname("trace",[PackageNamespace(""),Namespace("http://adobe.com/AS3/2006/builtin"),PackageNamespace("tests"),PackageInternalNs("tests"),PrivateNamespace("tests:TestManualConvert"),ProtectedNamespace("tests:TestManualConvert"),StaticProtectedNs("tests:TestManualConvert"),PrivateNamespace("TestManualConvert.as$0")]), 1 findpropstrict Multiname("trace",[PackageNamespace(""),Namespace("http://adobe.com/AS3/2006/builtin"),PackageNamespace("tests"),PackageInternalNs("tests"),PrivateNamespace("tests:TestManualConvert"),ProtectedNamespace("tests:TestManualConvert"),StaticProtectedNs("tests:TestManualConvert"),PrivateNamespace("TestManualConvert.as$0")]) getlocal0 - coerce_s + convert_s getproperty Multiname("length",[PackageNamespace(""),Namespace("http://adobe.com/AS3/2006/builtin"),PackageNamespace("tests"),PackageInternalNs("tests"),PrivateNamespace("tests:TestManualConvert"),ProtectedNamespace("tests:TestManualConvert"),StaticProtectedNs("tests:TestManualConvert"),PrivateNamespace("TestManualConvert.as$0")]) callpropvoid Multiname("trace",[PackageNamespace(""),Namespace("http://adobe.com/AS3/2006/builtin"),PackageNamespace("tests"),PackageInternalNs("tests"),PrivateNamespace("tests:TestManualConvert"),ProtectedNamespace("tests:TestManualConvert"),StaticProtectedNs("tests:TestManualConvert"),PrivateNamespace("TestManualConvert.as$0")]), 1 returnvoid diff --git a/libsrc/ffdec_lib/testexpected/as3_new/tests/TestNamedAnonFunctions.as b/libsrc/ffdec_lib/testexpected/as3_new/tests/TestNamedAnonFunctions.as index 5a24f0f4c..32e7888cf 100644 --- a/libsrc/ffdec_lib/testexpected/as3_new/tests/TestNamedAnonFunctions.as +++ b/libsrc/ffdec_lib/testexpected/as3_new/tests/TestNamedAnonFunctions.as @@ -54,7 +54,7 @@ package tests returns null body - maxstack 4 + maxstack 5 localcount 2 initscopedepth 5 maxscopedepth 8 @@ -74,7 +74,7 @@ package tests getscopeobject 1 newobject 0 pushwith - newfunction 2 + newfunction 3 dup getscopeobject 2 swap @@ -82,90 +82,128 @@ package tests popscope coerce_a setslot 1 + getlocal0 + pushbyte 5 + newobject 0 + pushwith + newfunction 4 + dup + getscopeobject 2 + swap + setproperty QName(PackageNamespace("tests"),"g") + popscope + callpropvoid QName(PrivateNamespace("tests:TestNamedAnonFunctions"),"f"), 2 + returnvoid + end ; code + end ; body + end ; method + } + + private function f(a:int, b:Function) : * + { + trait method QName(PrivateNamespace("tests:TestNamedAnonFunctions"),"f") + dispid 0 + method + name "tests:TestNamedAnonFunctions/private/f" + param QName(PackageNamespace(""),"int") + param QName(PackageNamespace(""),"Function") + returns null + + body + maxstack 1 + localcount 3 + initscopedepth 4 + maxscopedepth 5 + + code + getlocal0 + pushscope + debug 1, "a", 0, 0 + debug 1, "b", 1, 0 + returnvoid + end ; code + end ; body + end ; method + } + } + } + + class TestClass2 + { + + method + name "" + returns null + + body + maxstack 1 + localcount 1 + initscopedepth 3 + maxscopedepth 4 + + code + getlocal0 + pushscope + returnvoid + end ; code + end ; body + end ; method + + public var attrib1:int; + + public function TestClass2() + { + method + name "TestNamedAnonFunctions.as$0:TestClass2/TestClass2" + returns null + + body + maxstack 1 + localcount 1 + initscopedepth 4 + maxscopedepth 5 + + code + getlocal0 + pushscope + getlocal0 + constructsuper 0 returnvoid end ; code end ; body end ; method } } - } - - class TestClass2 - { method name "" returns null body - maxstack 1 + maxstack 2 localcount 1 - initscopedepth 3 - maxscopedepth 4 + initscopedepth 1 + maxscopedepth 3 code getlocal0 pushscope + findpropstrict Multiname("TestNamedAnonFunctions",[PackageNamespace("tests")]) + getlex QName(PackageNamespace(""),"Object") + pushscope + getlex QName(PackageNamespace(""),"Object") + newclass 0 + popscope + initproperty QName(PackageNamespace("tests"),"TestNamedAnonFunctions") + findpropstrict Multiname("TestClass2",[PrivateNamespace("TestNamedAnonFunctions.as$0")]) + getlex QName(PackageNamespace(""),"Object") + pushscope + getlex QName(PackageNamespace(""),"Object") + newclass 1 + popscope + initproperty QName(PrivateNamespace("TestNamedAnonFunctions.as$0"),"TestClass2") returnvoid end ; code end ; body end ; method - public var attrib1:int; - - public function TestClass2() - { - method - name "TestNamedAnonFunctions.as$0:TestClass2/TestClass2" - returns null - - body - maxstack 1 - localcount 1 - initscopedepth 4 - maxscopedepth 5 - - code - getlocal0 - pushscope - getlocal0 - constructsuper 0 - returnvoid - end ; code - end ; body - end ; method - } - } - - method - name "" - returns null - - body - maxstack 2 - localcount 1 - initscopedepth 1 - maxscopedepth 3 - - code - getlocal0 - pushscope - findpropstrict Multiname("TestNamedAnonFunctions",[PackageNamespace("tests")]) - getlex QName(PackageNamespace(""),"Object") - pushscope - getlex QName(PackageNamespace(""),"Object") - newclass 0 - popscope - initproperty QName(PackageNamespace("tests"),"TestNamedAnonFunctions") - findpropstrict Multiname("TestClass2",[PrivateNamespace("TestNamedAnonFunctions.as$0")]) - getlex QName(PackageNamespace(""),"Object") - pushscope - getlex QName(PackageNamespace(""),"Object") - newclass 1 - popscope - initproperty QName(PrivateNamespace("TestNamedAnonFunctions.as$0"),"TestClass2") - returnvoid - end ; code - end ; body - end ; method - diff --git a/libsrc/ffdec_lib/testexpected/as3_new/tests/TestNames.as b/libsrc/ffdec_lib/testexpected/as3_new/tests/TestNames.as index 99f90e9d0..a922ef143 100644 --- a/libsrc/ffdec_lib/testexpected/as3_new/tests/TestNames.as +++ b/libsrc/ffdec_lib/testexpected/as3_new/tests/TestNames.as @@ -103,13 +103,13 @@ package tests getlocal1 coerce QName(PackageNamespace(""),"Namespace") getlocal2 - coerce_s + convert_s convert_s findpropstrict RTQNameL() getlocal1 coerce QName(PackageNamespace(""),"Namespace") getlocal2 - coerce_s + convert_s convert_s getproperty RTQNameL() coerce_a diff --git a/libsrc/ffdec_lib/testexpected/as3_new/tests/TestStringCoerce.as b/libsrc/ffdec_lib/testexpected/as3_new/tests/TestStringCoerce.as index d2069f3c2..495b0e3c5 100644 --- a/libsrc/ffdec_lib/testexpected/as3_new/tests/TestStringCoerce.as +++ b/libsrc/ffdec_lib/testexpected/as3_new/tests/TestStringCoerce.as @@ -75,7 +75,7 @@ package tests getproperty QName(PrivateNamespace("tests:TestStringCoerce"),"a") pushstring "test" getproperty MultinameL([PackageNamespace(""),Namespace("http://adobe.com/AS3/2006/builtin"),PackageNamespace("tests"),PackageInternalNs("tests"),PrivateNamespace("tests:TestStringCoerce"),ProtectedNamespace("tests:TestStringCoerce"),StaticProtectedNs("tests:TestStringCoerce"),PrivateNamespace("TestStringCoerce.as$0")]) - coerce_s + convert_s coerce_s setlocal2 returnvoid diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/DocumentSearchData.java b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/DocumentSearchData.java index dcac9dd65..80ddc0935 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/DocumentSearchData.java +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/DocumentSearchData.java @@ -185,16 +185,22 @@ public class DocumentSearchData { int start = -1; int end = -1; int occurrenceNumber = 0; //JPEXS + boolean gotoLast = false; //JPEXS while (matcher.find()) { - if (matcher.end() >= dot) { - break; + if (!gotoLast //JPEXS + && matcher.end() > dot /* JPEXS: changed from >= */) { + if (end == -1 && isWrap()) { //JPEXS + gotoLast = true; //JPEXS + } else { + break; + } } occurrenceNumber++; start = matcher.start(); end = matcher.end(); } if (end > 0) { - target.select(start, end); + target.select(start, end); currentOccurrenceMap.put(target, occurrenceNumber); return true; } else { diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/Bundle_tr.properties b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/Bundle_tr.properties index 9d5c8d404..b48581b86 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/Bundle_tr.properties +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/Bundle_tr.properties @@ -40,5 +40,5 @@ ScriptRunnerAction.ErrorExecutingScript = Komut dosyas\u0131 \u00e7al\u0131\u015 ScriptRunnerAction.ScriptError = Komut Dosyas\u0131 Hatas\u0131 ScriptRunnerAction.ScriptEngineNotFound = [{0}] i\u00e7in komut dosyas\u0131 bulunamad\u0131. Bu eylem devre d\u0131\u015f\u0131 b\u0131rak\u0131ls\u0131n m\u0131? ShowAbbsAction.NoAbbsForType = Bu i\u00e7erik t\u00fcr\u00fc i\u00e7in k\u0131saltmalar yok -QuickFindDialog.Occurrences = (%current%/%total%) -QuickFindDialog.Occurrences.Zero = (0) +QuickFindDialog.Occurences = (%current%/%total%) +QuickFindDialog.Occurences.Zero = (0) diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/actions/gui/Bundle_tr.properties b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/actions/gui/Bundle_tr.properties new file mode 100644 index 000000000..5f303c143 --- /dev/null +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/actions/gui/Bundle_tr.properties @@ -0,0 +1,4 @@ +QuickFindDialog.jLblOccurrences.text = (0) +QuickFindDialog.jLblOccurrences.toolTipText = +QuickFindDialog.jLblOccurences.text = (0) +QuickFindDialog.jLblOccurences.AccessibleContext.accessibleName = Olu\u015fumlar diff --git a/resources/com.jpexs.decompiler.flash.metainfo.xml b/resources/com.jpexs.decompiler.flash.metainfo.xml index b96df49da..412ded45c 100644 --- a/resources/com.jpexs.decompiler.flash.metainfo.xml +++ b/resources/com.jpexs.decompiler.flash.metainfo.xml @@ -108,14 +108,14 @@
  • font normalizer uses 1024em (#2661)
  • null pointer on null caret in variable marker
  • push commands in as2 left in code (#2654)
  • -
  • deadlock on getcharacters vs drawframe (#2492)
  • +
  • deadlock on getCharacters vs drawFrame (#2492)
  • nullpointer on as3 deobfuscation
  • as3 deobfuscation - null values instead of registers (#2568, #2665)
  • stackoverflow on circular importassets (#2666)
  • allow add breakpoints on large classes (#2672)
  • unable to reset JNA temp directory (#2675)
  • svg shape export - use proper winding
  • -
  • properly normalize fonts in defineedittexts, kerning
  • +
  • properly normalize fonts in DefineEditTexts, kerning
  • properly draw edittext border, normalize size
  • illegal argument exception on creating morphshape from svg (#2676)
  • respect nofill argument in shape CLI SVG export (#2681)
  • diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index 092ad2db0..e3f61cac9 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -102,6 +102,7 @@ import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings; import com.jpexs.decompiler.flash.exporters.settings.SpriteExportSettings; import com.jpexs.decompiler.flash.exporters.settings.SymbolClassExportSettings; import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.XmlSwfExportSettings; import com.jpexs.decompiler.flash.exporters.swf.SwfToSwcExporter; import com.jpexs.decompiler.flash.exporters.swf.SwfXmlExporter; import com.jpexs.decompiler.flash.flexsdk.MxmlcAs3ScriptReplacer; @@ -701,7 +702,7 @@ public class CommandLineArgumentParser { parseDecrypt(args); System.exit(0); } else if (command.equals("swf2xml")) { - parseSwf2Xml(args, charset); + parseSwf2Xml(args, charset, handler); System.exit(0); } else if (command.equals("xml2swf")) { parseXml2Swf(args, charset); @@ -2711,15 +2712,58 @@ public class CommandLineArgumentParser { System.exit(result ? 0 : 1); } - private static void parseSwf2Xml(Stack args, String charset) { + private static void parseSwf2Xml(Stack args, String charset, AbortRetryIgnoreHandler handler) { if (args.size() < 2) { badArguments("swf2xml"); } + ScriptExportMode scriptExportMode = null; + ImageExportMode imageExportMode = null; + SoundExportMode soundExportMode = null; + + String arg = args.pop(); + if ("-external".equals(arg.toLowerCase(Locale.ENGLISH))) { + if (args.size() < 3) { + badArguments("swf2xml"); + } + String ext = args.pop(); + String[] parts = ext.split(",", -1); + + for (String part : parts) { + switch (part) { + case "as12script": + case "as12script:as": + scriptExportMode = ScriptExportMode.AS; + break; + case "image:png_gif_jpeg": + imageExportMode = ImageExportMode.PNG_GIF_JPEG; + break; + case "image": + case "image:png_gif_jpeg_alpha": + imageExportMode = ImageExportMode.PNG_GIF_JPEG_ALPHA; + break; + case "definesound": + case "definesound:mp3_wav_flv": + soundExportMode = SoundExportMode.MP3_WAV_FLV; + break; + case "all": + scriptExportMode = ScriptExportMode.AS; + imageExportMode = ImageExportMode.PNG_GIF_JPEG_ALPHA; + soundExportMode = SoundExportMode.MP3_WAV_FLV; + break; + default: + System.err.println("Unsupported external value: \"" + part + "\""); + badArguments("swf2xml"); + } + } + } else { + args.push(arg); + } + try { try (StdInAwareFileInputStream is = new StdInAwareFileInputStream(args.pop())) { SWF swf = new SWF(is, Configuration.parallelSpeedUp.get(), charset); - new SwfXmlExporter().exportXml(swf, new File(args.pop())); + new SwfXmlExporter().exportXml(swf, new File(args.pop()), new XmlSwfExportSettings(scriptExportMode, imageExportMode, soundExportMode), null, handler); } catch (FileNotFoundException ex) { System.err.println("File not found."); System.exit(1); @@ -2738,8 +2782,10 @@ public class CommandLineArgumentParser { try { SWF swf = new SWF(charset); - try (StdInAwareFileInputStream in = new StdInAwareFileInputStream(args.pop())) { - new SwfXmlImporter().importSwf(swf, in); + String fileName = args.pop(); + try (StdInAwareFileInputStream in = new StdInAwareFileInputStream(fileName)) { + File file = new File(StdInAwareFileInputStream.STDIN_PATH.equals(fileName) ? "." : fileName); + new SwfXmlImporter().importSwf(swf, in, file.getParentFile()); } try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(new File(args.pop())))) { swf.saveTo(fos); diff --git a/src/com/jpexs/decompiler/flash/console/help.txt b/src/com/jpexs/decompiler/flash/console/help.txt index 711b9095c..2e0303e3f 100644 --- a/src/com/jpexs/decompiler/flash/console/help.txt +++ b/src/com/jpexs/decompiler/flash/console/help.txt @@ -72,9 +72,19 @@ alias /? Decrypt HARMAN Air encrypted file. Decrypt HARMAN Air encrypted file and saves it to . --swf2xml +-swf2xml [-external ] Convert SWF to XML. Convert the SWF to XML file. + -external parameter sets which items will be available externally + Values for : Use comma separated list of following: + as12script:as + as12script (same as "as12script:as") + image:png_gif_jpeg + image:png_gif_jpeg_alpha + image (same as "image:png_gif_jpeg_alpha") + definesound:mp3_wav_flv + definesound (same as "definesound:mp3_wav_flv") + all (same as "as12script,image,definesound") -xml2swf Convert XML to SWF. @@ -376,7 +386,8 @@ Pre-options: font:woff - WOFF format for Fonts font4:cff - CFF format for DefineFont4 fla: or xfl: - Specify FLA format version - Values for : f5,mx,mx2004,f8,cs3,cs4,cs5,cs5.5,cs6,cc + Values for : + f1,f2,f3,f4,f5,mx,mx2004,f8,cs3,cs4,cs5,cs5.5,cs6,cc You can set multiple formats at once using comma (,) DO NOT PUT space between comma (,) and next value. The prefix with colon (:) is necessary. @@ -447,7 +458,7 @@ Pre-options: When it has .bin extension, legacy storage is used. -onerror (abort|retry |ignore) - Applies to: -export, -importScript + Applies to: -export, -importScript, -swf2xml Error handling mode. "abort" stops the exporting "retry" tries the exporting N times @@ -487,10 +498,6 @@ Pre-options: Applies to: -replace, -importScript Use AIR ("airglobal.swc") for AS3 compilation instead of "playerglobal.swc". --resamplewav - Applies to: -export - Enables resampling exported WAV sound files to 44kHz. - -ignorebackground Applies to: -export Ignores SWF background color when exporting frames diff --git a/src/com/jpexs/decompiler/flash/gui/ExportDialog.java b/src/com/jpexs/decompiler/flash/gui/ExportDialog.java index 3641d6c3b..cbb80ce62 100644 --- a/src/com/jpexs/decompiler/flash/gui/ExportDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/ExportDialog.java @@ -521,7 +521,7 @@ public class ExportDialog extends AppDialog { String key = optionNames[i] + "." + vals[j].toString().toLowerCase(Locale.ENGLISH); if (exportFormats.contains(key)) { - itemIndex = j; + itemIndex = namesList.size(); } namesList.add(new ComboValue(vals[j], translate(key))); diff --git a/src/com/jpexs/decompiler/flash/gui/FlaExportDialog.java b/src/com/jpexs/decompiler/flash/gui/FlaExportDialog.java new file mode 100644 index 000000000..d9b9e449a --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/FlaExportDialog.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2010-2026 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.SWF; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.xfl.FLAVersion; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.FlowLayout; +import java.awt.Window; +import java.awt.event.ActionEvent; +import javax.swing.BoxLayout; +import javax.swing.DefaultComboBoxModel; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; + +/** + * + * @author JPEXS + */ +public class FlaExportDialog extends AppDialog { + + private int result = ERROR_OPTION; + + private JComboBox combo; + + private JCheckBox compressedCheckBox; + + public FlaExportDialog(Window owner) { + super(owner); + setTitle(translate("dialog.title")); + + Container cnt = getContentPane(); + + + JPanel comboPanel = new JPanel(new FlowLayout()); + combo = new JComboBox<>(); + + combo.addActionListener(this::comboActionPerformed); + + combo.setRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + JLabel lab = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof FlaVersionItem) { + FLAVersion ver = ((FlaVersionItem) value).flaVersion; + lab.setIcon(View.getIcon("flash/" + ver.shortName().toLowerCase())); + } + return lab; + } + }); + + JLabel comboLabel = new JLabel(translate("version")); + comboPanel.add(comboLabel); + comboLabel.setLabelFor(combo); + comboPanel.add(combo); + comboPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + + compressedCheckBox = new JCheckBox(translate("compressed")); + compressedCheckBox.setAlignmentX(Component.CENTER_ALIGNMENT); + + + JPanel centerPanel = new JPanel(); + centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS)); + centerPanel.add(comboPanel); + centerPanel.add(compressedCheckBox); + + cnt.add(centerPanel, BorderLayout.CENTER); + + + JPanel buttonsPanel = new JPanel(new FlowLayout()); + JButton okButton = new JButton(translate("button.ok")); + okButton.addActionListener(this::okButtonActionPerformed); + + JButton cancelButton = new JButton(translate("button.cancel")); + cancelButton.addActionListener(this::cancelButtonActionPerformed); + + buttonsPanel.add(okButton); + buttonsPanel.add(cancelButton); + + cnt.add(buttonsPanel, BorderLayout.SOUTH); + pack(); + View.centerScreen(this); + View.setWindowIcon(this, "flash"); + getRootPane().setDefaultButton(okButton); + setModal(true); + } + + private void comboActionPerformed(ActionEvent e) { + int selectedIndex = combo.getSelectedIndex(); + if (selectedIndex > -1) { + + FlaVersionItem item = (FlaVersionItem) combo.getItemAt(selectedIndex); + if (item != null) { + if (item.flaVersion.xflVersion() == null) { + compressedCheckBox.setSelected(true); + } + compressedCheckBox.setEnabled(item.flaVersion.xflVersion() != null); + } + } + } + + + private class FlaVersionItem { + private final FLAVersion flaVersion; + private final boolean recommended; + + public FlaVersionItem(FLAVersion flaVersion, boolean recommended) { + this.flaVersion = flaVersion; + this.recommended = recommended; + } + + @Override + public String toString() { + return flaVersion.applicationName() + " " + (recommended ? translate("recommended") : ""); + } + } + + @Override + public void setVisible(boolean b) { + if (b) { + result = ERROR_OPTION; + } + super.setVisible(b); + } + + public boolean isCompressed() { + return compressedCheckBox.isSelected(); + } + + public FLAVersion getFlaVersion() { + if (combo.getSelectedItem() == null) { + return null; + } + return ((FlaVersionItem) combo.getSelectedItem()).flaVersion; + } + + private void okButtonActionPerformed(ActionEvent evt) { + result = OK_OPTION; + setVisible(false); + } + + private void cancelButtonActionPerformed(ActionEvent evt) { + result = CANCEL_OPTION; + setVisible(false); + } + + public int showExportDialog(SWF swf) { + DefaultComboBoxModel model = new DefaultComboBoxModel<>(); + boolean recommended = true; + boolean isAs3 = swf.isAS3(); + int recommendedIndex = -1; + for (FLAVersion ver : FLAVersion.values()) { + if (ver.minASVersion() == 3 && !isAs3) { + continue; + } + if (ver.maxASVersion() < 3 && isAs3) { + continue; + } + if (swf.version <= ver.maxSwfVersion()) { + model.addElement(new FlaVersionItem(ver, recommended)); + if (recommended) { + recommendedIndex = model.getSize() - 1; + } + recommended = false; + } else { + model.addElement(new FlaVersionItem(ver, false)); + } + } + combo.setModel(model); + if (recommendedIndex > -1) { + combo.setSelectedIndex(recommendedIndex); + compressedCheckBox.setSelected(Configuration.lastFlaExportCompressed.get()); + comboActionPerformed(null); + } + pack(); + setVisible(true); + return result; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 3df0f4cef..b64594aef 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -3895,7 +3895,7 @@ public class Main { for (int i = 0; i < arr.size(); i++) { JsonObject versionObj = arr.get(i).asObject(); String tagName = versionObj.get("tag_name").asString(); - if (currentVersion.equals(tagName) || stableTagName.equals(tagName)) { + if (currentTagName.equals(tagName) || stableTagName.equals(tagName)) { //Stop at current version, do not display more break; } diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameStatusPanel.java b/src/com/jpexs/decompiler/flash/gui/MainFrameStatusPanel.java index fd1ac7c0e..7404b8dba 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameStatusPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameStatusPanel.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.gui; +import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.helpers.CancellableWorker; import java.awt.BorderLayout; import java.awt.Cursor; @@ -81,8 +82,10 @@ public class MainFrameStatusPanel extends JPanel { if (w != null) { w.userCancel(true); } - }); - statusLeftPanel.add(loadingPanel); + }); + if (Configuration.showLoadingSpinner.get()) { + statusLeftPanel.add(loadingPanel); + } statusLeftPanel.add(cancelButton); statusLeftPanel.add(statusLabel); setPreferredSize(new Dimension(1, 30)); @@ -131,19 +134,23 @@ public class MainFrameStatusPanel extends JPanel { } public void showOldStatus() { - if (oldStatus.isEmpty()) { - loadingPanel.setVisible(false); - } else { - loadingPanel.setVisible(true); + if (Configuration.showLoadingSpinner.get()) { + if (oldStatus.isEmpty()) { + loadingPanel.setVisible(false); + } else { + loadingPanel.setVisible(true); + } } statusLabel.setText(oldStatus); } public void setWorkStatus(String s, CancellableWorker worker) { - if (s.isEmpty()) { - loadingPanel.setVisible(false); - } else { - loadingPanel.setVisible(true); + if (Configuration.showLoadingSpinner.get()) { + if (s.isEmpty()) { + loadingPanel.setVisible(false); + } else { + loadingPanel.setVisible(true); + } } statusLabel.setText(s); currentWorker = worker; diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 9640d4f69..661dbece2 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -92,6 +92,7 @@ import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings; import com.jpexs.decompiler.flash.exporters.settings.SpriteExportSettings; import com.jpexs.decompiler.flash.exporters.settings.SymbolClassExportSettings; import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.XmlSwfExportSettings; import com.jpexs.decompiler.flash.exporters.swf.SwfFlashDevelopExporter; import com.jpexs.decompiler.flash.exporters.swf.SwfIntelliJIdeaExporter; import com.jpexs.decompiler.flash.exporters.swf.SwfJavaExporter; @@ -3824,6 +3825,14 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (swf == null) { return; } + FlaExportDialog exportDialog = new FlaExportDialog(mainFrame.getWindow()); + if (exportDialog.showExportDialog(swf) != AppDialog.OK_OPTION) { + return; + } + + FLAVersion version = exportDialog.getFlaVersion(); + boolean compressed = exportDialog.isCompressed(); + JFileChooser fc = View.getFileChooserWithIcon("exportfla"); String selDir = Configuration.lastOpenDir.get(); fc.setCurrentDirectory(new File(selDir)); @@ -3836,9 +3845,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } String fileName; if (swfShortName.contains(".")) { - fileName = swfShortName.substring(0, swfShortName.lastIndexOf(".")) + ".fla"; + fileName = swfShortName.substring(0, swfShortName.lastIndexOf(".")) + (version == FLAVersion.F1 ? ".spa" : ".fla"); } else { - fileName = swfShortName + ".fla"; + fileName = swfShortName + (version == FLAVersion.F1 ? ".spa" : ".fla"); } final String fSwfShortName = swfShortName; @@ -3853,76 +3862,36 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se Map filterToFlaVersion = new HashMap<>(); FLAVersion lastVersion = FLAVersion.fromString(Configuration.lastFlaExportVersion.get("CS6")); - boolean lastCompressed = Configuration.lastFlaExportCompressed.get(true); - - for (int i = FLAVersion.values().length - 1; i >= 0; i--) { - final FLAVersion v = FLAVersion.values()[i]; - if (!isAS3 && v.minASVersion() > 2) { - // This version does not support AS1/2 - } else { - versions.add(v); - FileFilter f = new FileFilter() { - @Override - public boolean accept(File f) { - return f.isDirectory() || (f.getName().toLowerCase(Locale.ENGLISH).endsWith(".fla")); - } - - @Override - public String getDescription() { - return translate("filter.fla").replace("%version%", v.applicationName()); - } - }; - if (v == lastVersion && lastCompressed) { - fc.setFileFilter(f); - } else { - fc.addChoosableFileFilter(f); - } - filterToFlaVersion.put(f, v); - filterToVersion.put(f, "" + v); - filterToCompressed.put(f, true); - flaFilters.add(f); - - if (v.xflVersion() != null) { - f = new FileFilter() { - @Override - public boolean accept(File f) { - return f.isDirectory() || (f.getName().toLowerCase(Locale.ENGLISH).endsWith(".xfl")); - } - - @Override - public String getDescription() { - return translate("filter.xfl").replace("%version%", v.applicationName()); - } - }; - filterToFlaVersion.put(f, v); - filterToVersion.put(f, "" + v); - filterToCompressed.put(f, false); - - if (v == lastVersion && !lastCompressed) { - fc.setFileFilter(f); - } else { - fc.addChoosableFileFilter(f); - } - xflFilters.add(f); - } + FileFilter f = new FileFilter() { + @Override + public boolean accept(File f) { + return f.isDirectory() + || (!compressed && f.getName().toLowerCase(Locale.ENGLISH).endsWith(".xfl")) + || (compressed && version == FLAVersion.F1 && f.getName().toLowerCase(Locale.ENGLISH).endsWith(".spa")) + || (compressed && version != FLAVersion.F1 && f.getName().toLowerCase(Locale.ENGLISH).endsWith(".fla")); } - } + @Override + public String getDescription() { + if (!compressed) { + return translate("filter.xfl").replace("%version%", version.applicationName()); + } + return translate("filter.fla").replace("%version%", version.applicationName()); + } + }; + fc.setFileFilter(f); fc.setAcceptAllFileFilterUsed(false); if (fc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { - Configuration.lastFlaExportVersion.set(filterToVersion.get(fc.getFileFilter())); - Configuration.lastFlaExportCompressed.set(filterToCompressed.get(fc.getFileFilter())); + Configuration.lastFlaExportVersion.set(version.toString()); + Configuration.lastFlaExportCompressed.set(compressed); Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); File sf = Helper.fixDialogFile(fc.getSelectedFile()); - - FileFilter selectedFilter = fc.getFileFilter(); - final boolean compressed = flaFilters.contains(selectedFilter); + String path = sf.getAbsolutePath(); - if (path.endsWith(".fla") || path.endsWith(".xfl")) { + if (path.endsWith(".fla") || path.endsWith(".spa") || path.endsWith(".xfl")) { path = path.substring(0, path.length() - 4); } - path += compressed ? ".fla" : ".xfl"; - final FLAVersion selectedVersion = filterToFlaVersion.get(selectedFilter); + path += compressed ? (version == FLAVersion.F1 ? ".spa" : ".fla") : ".xfl"; final File selfile = new File(path); long timeBefore = System.currentTimeMillis(); new CancellableWorker("exportFla") { @@ -3946,9 +3915,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se try { AbortRetryIgnoreHandler errorHandler = new GuiAbortRetryIgnoreHandler(); if (compressed) { - swf.exportFla(errorHandler, selfile.getAbsolutePath(), fSwfShortName, ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion, prog); + swf.exportFla(errorHandler, selfile.getAbsolutePath(), fSwfShortName, ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), version, prog); } else { - swf.exportXfl(errorHandler, selfile.getAbsolutePath(), fSwfShortName, ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion, prog); + swf.exportXfl(errorHandler, selfile.getAbsolutePath(), fSwfShortName, ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), version, prog); } } catch (Exception ex) { logger.log(Level.SEVERE, "FLA export error", ex); @@ -4650,6 +4619,12 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se public void exportSwfXml(List items) { View.checkAccess(); + + XmlExportDialog dialog = new XmlExportDialog(Main.getDefaultDialogsOwner()); + if (dialog.showExportDialog() != AppDialog.OK_OPTION) { + return; + } + Set usedOpenables = new LinkedHashSet<>(); Set usedOpenableLists = new HashSet<>(); @@ -4710,6 +4685,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se return; } selFile = Helper.fixDialogFile(fc.getSelectedFile()).getAbsolutePath(); + + Configuration.lastExportDir.set(new File(selFile).getParentFile().getAbsolutePath()); + if (!selFile.toLowerCase(Locale.ENGLISH).endsWith(".xml")) { selFile = selFile + ".xml"; } @@ -4746,7 +4724,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se try { new RetryTask(() -> { File outFile = new File(selFile2); - new SwfXmlExporter().exportXml(openable, outFile); + XmlSwfExportSettings settings = new XmlSwfExportSettings(dialog.getEnumValue(ScriptExportMode.class), dialog.getEnumValue(ImageExportMode.class), dialog.getEnumValue(SoundExportMode.class)); + new SwfXmlExporter().exportXml(openable, outFile, settings, openable.getExportEventListener(), new GuiAbortRetryIgnoreHandler()); }, handler).run(); } catch (IOException ex) { @@ -4792,7 +4771,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se File selfile = Helper.fixDialogFile(selectedFile); try { try (FileInputStream fis = new FileInputStream(selfile)) { - new SwfXmlImporter().importSwf(swf, fis); + new SwfXmlImporter().importSwf(swf, fis, selfile.getParentFile()); } swf.clearAllCache(); swf.assignExportNamesToSymbols(); @@ -4801,8 +4780,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } catch (IOException ex) { logger.log(Level.SEVERE, null, ex); } - } - } + Main.stopWork(); + } + } } public void renameIdentifiers(final Openable openable) { diff --git a/src/com/jpexs/decompiler/flash/gui/SearchResultsStorage.java b/src/com/jpexs/decompiler/flash/gui/SearchResultsStorage.java index 363ed433b..3960cc7b7 100644 --- a/src/com/jpexs/decompiler/flash/gui/SearchResultsStorage.java +++ b/src/com/jpexs/decompiler/flash/gui/SearchResultsStorage.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.search.ActionSearchResult; import com.jpexs.decompiler.flash.search.ScriptNotFoundException; import com.jpexs.decompiler.flash.search.ScriptSearchResult; import com.jpexs.decompiler.flash.treeitems.Openable; +import com.jpexs.helpers.AllowedObjectInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -164,7 +165,7 @@ public class SearchResultsStorage { try { ByteArrayInputStream bais1 = new ByteArrayInputStream(itemData); int kind = bais1.read(); - ObjectInputStream ois = new ObjectInputStream(bais1); + ObjectInputStream ois = new AllowedObjectInputStream(bais1); List resultData = readByteList(ois); for (int i = 0; i < resultData.size(); i++) { try { @@ -194,7 +195,7 @@ public class SearchResultsStorage { public synchronized void load() throws IOException { String configFile = getConfigFile(); if (new File(configFile).exists()) { - try (FileInputStream fis = new FileInputStream(configFile); ObjectInputStream ois = new ObjectInputStream(fis)) { + try (FileInputStream fis = new FileInputStream(configFile); ObjectInputStream ois = new AllowedObjectInputStream(fis)) { int major = ois.read(); ois.read(); // minor if (major != SERIAL_VERSION_MAJOR) { //incompatible version diff --git a/src/com/jpexs/decompiler/flash/gui/View.java b/src/com/jpexs/decompiler/flash/gui/View.java index 10f8e2566..5c8be0896 100644 --- a/src/com/jpexs/decompiler/flash/gui/View.java +++ b/src/com/jpexs/decompiler/flash/gui/View.java @@ -523,7 +523,8 @@ public class View { } public static ImageIcon getIcon(String name) { - return new ImageIcon(View.class.getClassLoader().getResource("com/jpexs/decompiler/flash/gui/graphics/" + name + ".png")); + String path = "com/jpexs/decompiler/flash/gui/graphics/" + name + ".png"; + return new ImageIcon(View.class.getClassLoader().getResource(path)); } private static final KeyStroke escapeStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); diff --git a/src/com/jpexs/decompiler/flash/gui/XmlExportDialog.java b/src/com/jpexs/decompiler/flash/gui/XmlExportDialog.java new file mode 100644 index 000000000..4542c63e5 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/XmlExportDialog.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2010-2026 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.exporters.modes.ImageExportMode; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode; +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import javax.swing.ComboBoxModel; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; + +/** + * + * @author JPEXS + */ +public class XmlExportDialog extends AppDialog { + private int result = ERROR_OPTION; + + private final Map, JComboBox> combos = new HashMap<>(); + + private final Map, String> enumNames = new HashMap<>(); + + private final List allDefaults = Arrays.asList(ScriptExportMode.AS, ImageExportMode.PNG_GIF_JPEG_ALPHA, SoundExportMode.MP3_WAV_FLV); + + public XmlExportDialog(Window owner) { + super(owner); + + enumNames.put(ScriptExportMode.class, "as12script"); + enumNames.put(ImageExportMode.class, "image"); + enumNames.put(SoundExportMode.class, "definesound"); + setTitle(translate("dialog.title")); + JPanel buttonsPanel = new JPanel(new FlowLayout()); + JButton okButton = new JButton(translate("button.ok")); + okButton.addActionListener(this::okButtonActionPerformed); + JButton cancelButton = new JButton(translate("button.cancel")); + cancelButton.addActionListener(this::cancelButtonActionPerformed); + buttonsPanel.add(okButton); + buttonsPanel.add(cancelButton); + + JPanel centralPanel = new JPanel(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + + gbc.gridx = 0; + gbc.gridy = 0; + gbc.insets = new Insets(1, 2, 1, 2); + + JLabel selectLabel = new JLabel(translate("selectExternal")); + gbc.gridwidth = 4; + centralPanel.add(selectLabel, gbc); + + gbc.gridwidth = 1; + gbc.gridy++; + + DefaultComboBoxModel as12ScriptsModel = new DefaultComboBoxModel<>(); + as12ScriptsModel.addElement(new ComboValue(null, translate("xml"))); + as12ScriptsModel.addElement(new ComboValue(ScriptExportMode.AS, translateExport("scripts.as"))); + + addComboRow(centralPanel, gbc, translate("as12scripts"), "as", as12ScriptsModel, ScriptExportMode.class); + + DefaultComboBoxModel imageModel = new DefaultComboBoxModel<>(); + imageModel.addElement(new ComboValue(null, translate("xml"))); + imageModel.addElement(new ComboValue(ImageExportMode.PNG_GIF_JPEG, translateExport("images.png_gif_jpeg"))); + imageModel.addElement(new ComboValue(ImageExportMode.PNG_GIF_JPEG_ALPHA, translateExport("images.png_gif_jpeg_alpha"))); + + addComboRow(centralPanel, gbc, translateExport("images"), "image", imageModel, ImageExportMode.class); + + DefaultComboBoxModel soundModel = new DefaultComboBoxModel<>(); + soundModel.addElement(new ComboValue(null, translate("xml"))); + soundModel.addElement(new ComboValue(SoundExportMode.MP3_WAV_FLV, translateExport("sounds.mp3_wav_flv"))); + + addComboRow(centralPanel, gbc, translate("defineSound"), "sound", soundModel, SoundExportMode.class); + + + + String config = Configuration.lastSelectedXmlExportFormats.get(); + if (!config.isEmpty()) { + String[] parts = config.split(",", -1); + for (String part : parts) { + String[] parts2 = part.split("\\.", -1); + if (parts2.length != 2) { + continue; + } + String name = parts2[0]; + String value = parts2[1]; + for (Class cls : combos.keySet()) { + if (enumNames.get(cls).equals(name)) { + JComboBox combo = combos.get(cls); + DefaultComboBoxModel model = (DefaultComboBoxModel) combo.getModel(); + for (int i = 0; i < model.getSize(); i++) { + ComboValue cv = model.getElementAt(i); + if (cv.value == null && value.equals("none")) { + combo.setSelectedIndex(0); + break; + } + if (cv.value != null && cv.value.toString().toLowerCase(Locale.ENGLISH).equals(value)) { + combo.setSelectedIndex(i); + break; + } + } + break; + } + } + } + } + + JButton allButton = new JButton(translate("all")); + allButton.addActionListener(this::allButtonActionPerformed); + + JButton noneButton = new JButton(translate("none")); + noneButton.addActionListener(this::noneButtonActionPerformed); + + + gbc.gridx = 2; + gbc.insets = new Insets(5, 2, 1, 2); + gbc.anchor = GridBagConstraints.CENTER; + centralPanel.add(noneButton, gbc); + gbc.gridx++; + centralPanel.add(allButton, gbc); + + Container cnt = getContentPane(); + cnt.setLayout(new BorderLayout()); + cnt.add(centralPanel, BorderLayout.CENTER); + cnt.add(buttonsPanel, BorderLayout.SOUTH); + + pack(); + View.centerScreen(this); + View.setWindowIcon(this, "exportxml"); + getRootPane().setDefaultButton(okButton); + setModal(true); + } + + private void addComboRow(JPanel centralPanel, GridBagConstraints gbc, String label, String icon, ComboBoxModel model, Class enumClass) { + gbc.fill = GridBagConstraints.NONE; + + JLabel scriptsLabel = new JLabel(label); + scriptsLabel.setIcon(View.getIcon(icon + "16")); + scriptsLabel.setHorizontalTextPosition(SwingConstants.LEFT); + gbc.anchor = GridBagConstraints.LINE_END; + centralPanel.add(scriptsLabel, gbc); + + gbc.gridx++; + JLabel arrowLabel = new JLabel(translateExport("arrow")); + gbc.insets = new Insets(1, 5, 1, 5); + gbc.anchor = GridBagConstraints.CENTER; + centralPanel.add(arrowLabel, gbc); + + gbc.insets = new Insets(1, 2, 1, 2); + + gbc.gridx++; + gbc.gridwidth = 2; + JComboBox combo = new JComboBox<>(model); + gbc.anchor = GridBagConstraints.LINE_START; + gbc.fill = GridBagConstraints.BOTH; + + combos.put(enumClass, combo); + + centralPanel.add(combo, gbc); + gbc.gridy++; + gbc.gridwidth = 1; + gbc.gridx = 0; + gbc.fill = GridBagConstraints.NONE; + } + + + public > T getEnumValue(Class cls) { + if (!combos.containsKey(cls)) { + return null; + } + ComboValue cv = (ComboValue) combos.get(cls).getSelectedItem(); + if (cv == null) { + return null; + } + @SuppressWarnings("unchecked") + T ret = (T) cv.value; + return ret; + } + + private void okButtonActionPerformed(ActionEvent evt) { + + List vals = new ArrayList<>(); + for (Class cls : combos.keySet()) { + String name = enumNames.get(cls); + ComboValue cv = (ComboValue) combos.get(cls).getSelectedItem(); + if (cv == null || cv.value == null) { + vals.add(name + "." + "none"); + } else { + vals.add(name + "." + cv.value.toString().toLowerCase()); + } + } + Configuration.lastSelectedXmlExportFormats.set(String.join(",", vals)); + + result = OK_OPTION; + setVisible(false); + } + + private void noneButtonActionPerformed(ActionEvent evt) { + for (Class cls : combos.keySet()) { + JComboBox combo = combos.get(cls); + combo.setSelectedIndex(0); + } + } + + private void allButtonActionPerformed(ActionEvent evt) { + for (Class cls : combos.keySet()) { + JComboBox combo = combos.get(cls); + DefaultComboBoxModel model = (DefaultComboBoxModel) combo.getModel(); + for (int i = 0; i < model.getSize(); i++) { + ComboValue value = model.getElementAt(i); + if (value.value != null && allDefaults.contains(value.value)) { + combo.setSelectedIndex(i); + break; + } + } + } + } + + private void cancelButtonActionPerformed(ActionEvent evt) { + result = CANCEL_OPTION; + setVisible(false); + } + + public int showExportDialog() { + setVisible(true); + return result; + } + + private String translateExport(String key) { + return AppDialog.translateForDialog(key, ExportDialog.class); + } + + private class ComboValue { + + public Object value; + public String text; + + public ComboValue(Object value, String text) { + this.value = value; + this.text = text; + } + + @Override + public String toString() { + return text; + } + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/cc.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/cc.png new file mode 100644 index 000000000..2f41bf921 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/cc.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs3.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs3.png new file mode 100644 index 000000000..b28164e48 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs3.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs4.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs4.png new file mode 100644 index 000000000..33f708ade Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs4.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs5.5.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs5.5.png new file mode 100644 index 000000000..8b47b20e7 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs5.5.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs5.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs5.png new file mode 100644 index 000000000..8b47b20e7 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs5.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs6.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs6.png new file mode 100644 index 000000000..d04e9f565 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/cs6.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/f1.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/f1.png new file mode 100644 index 000000000..bb845b8e8 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/f1.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/f2.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/f2.png new file mode 100644 index 000000000..7782a3934 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/f2.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/f3.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/f3.png new file mode 100644 index 000000000..8d453dd2a Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/f3.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/f4.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/f4.png new file mode 100644 index 000000000..8e8cb8e78 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/f4.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/f5.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/f5.png new file mode 100644 index 000000000..d99f32536 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/f5.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/f8.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/f8.png new file mode 100644 index 000000000..19facbdd0 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/f8.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/mx.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/mx.png new file mode 100644 index 000000000..a9797cb53 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/mx.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/flash/mx2004.png b/src/com/jpexs/decompiler/flash/gui/graphics/flash/mx2004.png new file mode 100644 index 000000000..93489c82c Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/flash/mx2004.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties index c4e1864d3..f01554800 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties @@ -694,3 +694,10 @@ config.description.msaaGridForExport = Multi sample Anti-aliasing grid size NxN config.name.useMinimumStrokeWidth1Px = Minimum stroke width of 1 pixel (As in Flash) config.description.useMinimumStrokeWidth1Px = Use 1 pixel as minimal stroke width. Flash renders strokes this way. Turn this off to allow thinner strokes. + +#after 26.0.0 +config.name.showLoadingSpinner = Show loading spinner +config.description.showLoadingSpinner = Displays animated loading indicator in status bar + +config.name.xmlExport.formats = (Internal) Xml export external formats +config.description.xmlExport.formats = Last used Xml export external formats. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties index 90fd293e3..0463e6ea0 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties @@ -694,3 +694,10 @@ config.description.msaaGridForExport = Velikost m\u0159\u00ed\u017eky v\u00edcen config.name.useMinimumStrokeWidth1Px = Minim\u00e1ln\u00ed \u0161\u00ed\u0159ka tahu 1 pixel (jako ve Flashi) config.description.useMinimumStrokeWidth1Px = Pou\u017e\u00edt 1 pixel jako minim\u00e1ln\u00ed \u0161\u00ed\u0159ku tahu. Flash vykresluje tahy t\u00edmto zp\u016fsobem. Vypn\u011bte pro umo\u017en\u011bn\u00ed ten\u010d\u00edch tah\u016f. + +#after 26.0.0 +config.name.showLoadingSpinner = Zobrazit indik\u00e1tor na\u010d\u00edt\u00e1n\u00ed +config.description.showLoadingSpinner = Zobraz\u00ed animovan\u00fd indik\u00e1tor na\u010d\u00edt\u00e1n\u00ed ve stavov\u00e9m \u0159\u00e1dku + +config.name.xmlExport.formats = (Intern\u00ed) Form\u00e1ty extern\u00edho XML exportu +config.description.xmlExport.formats = Naposledy pou\u017eit\u00e9 form\u00e1ty extern\u00edho XML exportu. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_de.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_de.properties index 676336e06..28461879e 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_de.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_de.properties @@ -623,3 +623,10 @@ config.description.msaaGridForExport = Rastergr\u00f6\u00dfe NxN pro Multisample config.name.useMinimumStrokeWidth1Px = Minimale Strichbreite von 1 Pixel (wie in Flash) config.description.useMinimumStrokeWidth1Px = 1 Pixel als minimale Strichbreite verwenden. Flash rendert Striche auf diese Weise. Deaktivieren, um d\u00fcnnere Striche zu erm\u00f6glichen. + +#after 26.0.0 +config.name.showLoadingSpinner = Ladeanzeige anzeigen +config.description.showLoadingSpinner = Zeigt eine animierte Ladeanzeige in der Statusleiste an + +config.name.xmlExport.formats = (Intern) Formate f\u00fcr externen XML-Export +config.description.xmlExport.formats = Zuletzt verwendete Formate f\u00fcr externen XML-Export. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_sk.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_sk.properties index 58ac75343..5c7db62c9 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_sk.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_sk.properties @@ -694,3 +694,10 @@ config.description.msaaGridForExport = Ve\u013ekos\u0165 mrie\u017eky viacn\u00e config.name.useMinimumStrokeWidth1Px = Minim\u00e1lna \u0161\u00edrka \u0165ahu 1 pixel (ako vo Flashi) config.description.useMinimumStrokeWidth1Px = Pou\u017ei\u0165 1 pixel ako minim\u00e1lnu \u0161\u00edrku \u0165ahu. Flash vykres\u013euje \u0165ahy t\u00fdmto sp\u00f4sobom. Vypnite pre umo\u017enenie ten\u0161\u00edch \u0165ahov. + +#after 26.0.0 +config.name.showLoadingSpinner = Zobrazi\u0165 indik\u00e1tor na\u010d\u00edtania +config.description.showLoadingSpinner = Zobraz\u00ed animovan\u00fd indik\u00e1tor na\u010d\u00edtania v stavovom riadku + +config.name.xmlExport.formats = (Intern\u00e9) Form\u00e1ty extern\u00e9ho XML exportu +config.description.xmlExport.formats = Naposledy pou\u017eit\u00e9 form\u00e1ty extern\u00e9ho XML exportu. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_sl.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_sl.properties index c4fee2758..cc02aa541 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_sl.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_sl.properties @@ -623,3 +623,21 @@ config.name.showDebugListenInfo = Prika\u017ei informacije pred poslu\u0161anjem config.description.showDebugListenInfo = Prika\u017ee nekaj informacij o delovanju poslu\u0161anja odpravljanja napak po kliku na Poslu\u0161aj odpravljanje napak v meniju. config.name.as3QNameObfuscatedPropsInSquareBrackets = V oklepajih prika\u017ei zakrite lastnosti QName v AS3 config.description.as3QNameObfuscatedPropsInSquareBrackets = Prika\u017ee zakrite lastnosti QName v AS3 kot nize v oklepajih. +#after 25.1.2 +config.name.sortDebugVariablesAlphabetically = Razvrsti spremenljivke v razhro\u0161\u010devalniku +config.description.sortDebugVariablesAlphabetically = Razvrsti spremenljivke v razhro\u0161\u010devalniku po abecedi. +config.name.svgExportGaussianBlur = Uporabi Gaussovo zameglitev pri izvozu SVG +config.description.svgExportGaussianBlur = Pri izvozu SVG uporabi Gaussovo zameglitev namesto \u0161katlaste zameglitve (ki uporablja konvolucijsko matriko). \u0160katlasta zameglitev povzro\u010da te\u017eave s skaliranjem v nekaterih brskalnikih. Gaussova zameglitev pa ni 100 % natan\u010dna glede na to, kar prikazuje SWF. +#after 25.1.3 +config.name.exportFlaAs3DisableScriptLayer = Izvoz FLA - AS3 - onemogo\u010di plast skripta +config.description.exportFlaAs3DisableScriptLayer = Pri izvozu v FLA formatu ActionScript 3 bodo skripti v okvirjih ostali znotraj razreda, ki mu pripadajo, namesto da bi bili lo\u010deno postavljeni v plast Script. True = v razredu, False = v plasti Script. +config.name.useMsaaForDisplay = Uporabi ve\u010dvzor\u010dno glajenje (prikaz) +config.description.useMsaaForDisplay = Za prikaz uporabi ve\u010dvzor\u010dno glajenje 4x4. +config.name.useMsaaForExport = Uporabi ve\u010dvzor\u010dno glajenje (izvoz) +config.description.useMsaaForExport = Za izvoz uporabi ve\u010dvzor\u010dno glajenje robov 4x4. +config.name.msaaGridForDisplay = Ve\u010dvzor\u010dna mre\u017ea za glajenje robov (prikaz) +config.description.msaaGridForDisplay = Ve\u010dvzor\u010dna mre\u017ea za glajenje robov velikosti NxN za namene prikaza. +config.name.msaaGridForExport = Ve\u010dvzor\u010dna mre\u017ea za glajenje robov (izvoz) +config.description.msaaGridForExport = Ve\u010dvzor\u010dna mre\u017ea za glajenje robov velikosti NxN za namene prikaza. +config.name.useMinimumStrokeWidth1Px = Najmanj\u0161a \u0161irina poteze je 1 slikovna pika (kot v Flashu) +config.description.useMinimumStrokeWidth1Px = Za minimalno \u0161irino poteze uporabi 1 slikovno piko. Flash upodablja poteze na ta na\u010din. Izklopi to mo\u017enost, da omogo\u010di\u0161 tanj\u0161e poteze. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_tr.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_tr.properties index 2dcae9935..6e2b63416 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_tr.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_tr.properties @@ -596,4 +596,48 @@ config.name.showCodeCompletionOnDot = Nokta(.) tu\u015funa bas\u0131ld\u0131\u01 config.description.showCodeCompletionOnDot = Nokta(.) tu\u015funa bas\u0131ld\u0131\u011f\u0131nda kod tamamlama penceresini otomatik olarak g\u00f6ster. Devre d\u0131\u015f\u0131 b\u0131rak\u0131ld\u0131\u011f\u0131nda Ctrl+bo\u015fluk tu\u015fu ile g\u00f6sterilebilir. #after 24.0.1 config.name.skipDetectionOfUninitializedClassFields = AS2: Ba\u015flat\u0131lmam\u0131\u015f s\u0131n\u0131f alanlar\u0131n\u0131n alg\u0131lanmas\u0131n\u0131 atla -config.description.skipDetectionOfUninitializedClassFields = AS2 s\u0131n\u0131flar\u0131nda ba\u015flat\u0131lmam\u0131\u015f \u00f6zniteliklerin alg\u0131lanmas\u0131n\u0131 atlar; bu, herhangi bir s\u0131n\u0131fa eri\u015fmeden \u00f6nce ge\u00e7erli SWF'deki t\u00fcm komut dosyalar\u0131n\u0131n derlenmesini i\u00e7erir. B\u00fcy\u00fck bir gizlenmi\u015f dosyan\u0131z varsa ve en az\u0131ndan bir \u015fey g\u00f6rmek istiyorsan\u0131z (= tamamlanmam\u0131\u015f s\u0131n\u0131f) bunu do\u011fru olarak ayarlay\u0131n. +config.description.skipDetectionOfUninitializedClassFields = AS2 s\u0131n\u0131flar\u0131ndaki ba\u015flat\u0131lmam\u0131\u015f \u00f6zniteliklerin tespitini atlar; bu, herhangi bir s\u0131n\u0131fa eri\u015fmeden \u00f6nce mevcut SWF'deki t\u00fcm komut dosyalar\u0131n\u0131n derlenmesini i\u00e7erir. B\u00fcy\u00fck bir gizlenmi\u015f dosyan\u0131z varsa ve en az\u0131ndan bir \u015feyler g\u00f6rmek istiyorsan\u0131z (= eksik s\u0131n\u0131f) bunu true olarak ayarlay\u0131n. +config.name.showHeapStatusWidget = Y\u0131\u011f\u0131n durumu minik arac\u0131n\u0131 g\u00f6ster +config.description.showHeapStatusWidget = Ba\u015fl\u0131k \u00e7ubu\u011funda kullan\u0131lan bellek minik arac\u0131n\u0131 g\u00f6r\u00fcnt\u00fcler. +config.name.autoDeobfuscateIdentifiers = Tan\u0131mlay\u0131c\u0131lar\u0131n gizlenmesini kald\u0131r +config.description.autoDeobfuscateIdentifiers = Ge\u00e7erli tan\u0131mlay\u0131c\u0131 olmayan gizlenmi\u015f adlar, _SafeStr_XX, _SafeCls_XX veya _SafePkg_XX olarak yazd\u0131r\u0131l\u0131r. +config.name.showVarsWithDontEnumerateFlag = Hata ay\u0131klay\u0131c\u0131 - DontEnumerate bayra\u011f\u0131na sahip de\u011fi\u015fkenleri g\u00f6ster +config.description.showVarsWithDontEnumerateFlag = ActionScript'te hata ay\u0131klarken, Flash'\u0131n dahili olan \u00f6zel DontEnumerate bayra\u011f\u0131na sahip de\u011fi\u015fkenleri de g\u00f6sterir. Genellikle alakal\u0131 olmad\u0131klar\u0131 i\u00e7in bunlar\u0131 gizlemeniz \u00f6nerilir. +config.name.allowDragAndDropFromResourcesTree = Kaynaklar g\u00f6r\u00fcn\u00fcm\u00fc a\u011fac\u0131ndan s\u00fcr\u00fckle ve b\u0131rak \u00f6zelli\u011fine izin ver +config.description.allowDragAndDropFromResourcesTree = Kaynaklar g\u00f6r\u00fcn\u00fcm a\u011fac\u0131ndan \u00f6\u011feleri d\u0131\u015fa aktarmak i\u00e7in s\u00fcr\u00fckle ve b\u0131rak \u00f6zelli\u011fini etkinle\u015ftir. Mac OS'ta, s\u00fcr\u00fckleme ba\u015flamadan \u00f6nce t\u00fcm dosyalar\u0131n d\u0131\u015fa aktar\u0131lmas\u0131 gerekti\u011finden s\u00fcr\u00fckleme i\u015flemi can s\u0131k\u0131c\u0131d\u0131r.Yanl\u0131\u015fl\u0131kla s\u00fcr\u00fckleyip uygulaman\u0131n donmas\u0131n\u0131 \u00f6nlemek i\u00e7in bunu false olarak ayarlay\u0131n. +config.name.reduceAntialiasConflationByScalingForDisplay = \u00d6l\u00e7eklendirme ile kenar yumu\u015fatma kaynakl\u0131 birle\u015fmeyi azalt\u0131n (G\u00f6r\u00fcnt\u00fcleme) +config.description.reduceAntialiasConflationByScalingForDisplay = Daha b\u00fcy\u00fck bir g\u00f6r\u00fcnt\u00fc \u00fcreterek ve ard\u0131ndan k\u00fc\u00e7\u00fclterek kenar yumu\u015fatman\u0131n neden oldu\u011fu birle\u015fme bozukluklar\u0131n\u0131 azalt\u0131r. Derleyici taraf\u0131ndan g\u00f6r\u00fcnt\u00fclenmesi i\u00e7in kullan\u0131l\u0131r. +config.name.reduceAntialiasConflationByScalingValueForDisplay = Kenar yumu\u015fatma kaynakl\u0131 birle\u015fmeyi azaltmak i\u00e7in maksimum \u00f6l\u00e7ek de\u011feri (G\u00f6r\u00fcnt\u00fcleme) +config.description.reduceAntialiasConflationByScalingValueForDisplay = Kenar yumu\u015fatma kaynakl\u0131 birle\u015fmeyi azaltmak i\u00e7in maksimum \u00f6l\u00e7ek katsay\u0131s\u0131. Derleyici taraf\u0131ndan g\u00f6r\u00fcnt\u00fclenmesi i\u00e7in kullan\u0131l\u0131r. Daha b\u00fcy\u00fck de\u011fer = daha yava\u015f g\u00f6r\u00fcnt\u00fcleme, ancak daha do\u011fru sonu\u00e7, ayr\u0131ca daha fazla bellek kullan\u0131r. 1 = yok, 10 = optimal, 20 = m\u00fckemmel. Ger\u00e7ek de\u011feri, g\u00f6r\u00fcnt\u00fclerin boyutuna ba\u011fl\u0131 olarak daha d\u00fc\u015f\u00fck olabilir. +config.name.reduceAntialiasConflationByScalingForExport = \u00d6l\u00e7eklendirme ile kenar yumu\u015fatma kaynakl\u0131 birle\u015fmeyi azalt\u0131n (D\u0131\u015fa Aktar) +config.description.reduceAntialiasConflationByScalingForExport = Daha b\u00fcy\u00fck bir g\u00f6r\u00fcnt\u00fc \u00fcreterek ve ard\u0131ndan k\u00fc\u00e7\u00fclterek kenar yumu\u015fatman\u0131n neden oldu\u011fu birle\u015fme bozukluklar\u0131n\u0131 azalt\u0131r. D\u0131\u015fa aktarma i\u00e7in kullan\u0131l\u0131r. +config.name.reduceAntialiasConflationByScalingValueForExport = Kenar yumu\u015fatma birle\u015ftirmesini azaltmak i\u00e7in maksimum \u00f6l\u00e7ek de\u011feri (D\u0131\u015fa Aktar) +config.description.reduceAntialiasConflationByScalingValueForExport = Kenar yumu\u015fatma birle\u015ftirmesini azaltmak i\u00e7in maksimum \u00f6l\u00e7ek katsay\u0131s\u0131. D\u0131\u015fa aktarma i\u00e7in kullan\u0131l\u0131r. Daha b\u00fcy\u00fck de\u011fer = daha yava\u015f d\u0131\u015fa aktarma, ancak daha do\u011fru sonu\u00e7, ayr\u0131ca daha fazla bellek kullan\u0131r. 1 = yok, 10 = optimal, 20 = m\u00fckemmel. Ger\u00e7ek de\u011feri, g\u00f6r\u00fcnt\u00fclerin boyutuna ba\u011fl\u0131 olarak daha d\u00fc\u015f\u00fck olabilir. +#after 24.1.2 +config.name.lastExportMorphDuration = D\u0131\u015fa Aktarma morfoloji s\u00fcresinin son ayar\u0131 +config.description.lastExportMorphDuration = D\u0131\u015fa aktarma morfoloji s\u00fcresinin saniye cinsinden son ayar\u0131 (ondal\u0131k say\u0131). +config.name.lastExportMorphNumberOfFrames = D\u0131\u015fa Aktarma morfoloji kare say\u0131s\u0131n\u0131n son ayar\u0131 +config.description.lastExportMorphNumberOfFrames = D\u0131\u015fa aktarma morfoloji kare say\u0131s\u0131n\u0131n son ayar\u0131. +#after 25.0.0 +config.name.showDebugListenInfo = Hata ay\u0131klama dinlemesinden \u00f6nce bilgi g\u00f6ster +config.description.showDebugListenInfo = Men\u00fcde Hata ay\u0131klama dinlemesini t\u0131klad\u0131ktan sonra hata ay\u0131klama dinlemesinin nas\u0131l \u00e7al\u0131\u015ft\u0131\u011f\u0131 hakk\u0131nda baz\u0131 bilgiler g\u00f6r\u00fcnt\u00fcler. +config.name.as3QNameObfuscatedPropsInSquareBrackets = Parantez i\u00e7inde AS3 gizlenmi\u015f QName \u00f6zelliklerini g\u00f6ster +config.description.as3QNameObfuscatedPropsInSquareBrackets = AS3 gizlenmi\u015f QName \u00f6zelliklerini parantez i\u00e7inde dizeler olarak g\u00f6r\u00fcnt\u00fcler. +#after 25.1.2 +config.name.sortDebugVariablesAlphabetically = Hata ay\u0131klay\u0131c\u0131daki de\u011fi\u015fkenleri s\u0131rala +config.description.sortDebugVariablesAlphabetically = Hata ay\u0131klay\u0131c\u0131daki de\u011fi\u015fkenleri alfabetik olarak s\u0131ralar. +config.name.svgExportGaussianBlur = SVG d\u0131\u015fa aktar\u0131m\u0131nda Gauss bulan\u0131kl\u0131\u011f\u0131 kullan\u0131n +config.description.svgExportGaussianBlur = SVG d\u0131\u015fa aktar\u0131mlar\u0131nda kutu bulan\u0131kl\u0131\u011f\u0131 (konvol\u00fcsyon matrisi kullan\u0131r) yerine Gauss bulan\u0131kl\u0131\u011f\u0131 kullan\u0131n. Kutu bulan\u0131kl\u0131\u011f\u0131 baz\u0131 taray\u0131c\u0131larda \u00f6l\u00e7eklendirme sorunlar\u0131na neden olur. \u00d6te yandan Gauss bulan\u0131kl\u0131\u011f\u0131, SWF'nin g\u00f6sterdi\u011fiyle %100 do\u011fru de\u011fildir. +#after 25.1.3 +config.name.exportFlaAs3DisableScriptLayer = FLA d\u0131\u015fa aktar\u0131m\u0131 - AS3 - komut dosyas\u0131 katman\u0131n\u0131 devre d\u0131\u015f\u0131 b\u0131rak +config.description.exportFlaAs3DisableScriptLayer = ActionScript 3 FLA d\u0131\u015fa aktar\u0131m\u0131nda, \u00e7er\u00e7evelerdeki komut dosyalar\u0131, ayr\u0131 bir Komut Dosyas\u0131 katman\u0131na yerle\u015ftirilmek yerine, ait olduklar\u0131 s\u0131n\u0131f\u0131n i\u00e7inde kal\u0131r. True = s\u0131n\u0131fta, False = Komut Dosyas\u0131 katman\u0131nda. +config.name.useMsaaForDisplay = \u00c7oklu \u00d6rnek Kenar Yumu\u015fatma (G\u00f6r\u00fcnt\u00fcleme) kullan +config.description.useMsaaForDisplay = G\u00f6r\u00fcnt\u00fcleme amac\u0131yla 4x4 \u00c7oklu \u00d6rnek Kenar Yumu\u015fatma kullan\u0131n. +config.name.useMsaaForExport = \u00c7oklu \u00d6rnek Kenar Yumu\u015fatma (D\u0131\u015fa Aktarma) kullan +config.description.useMsaaForExport = D\u0131\u015fa aktarma amac\u0131yla 4x4 \u00c7oklu \u00d6rnek Kenar Yumu\u015fatma kullan\u0131n. +config.name.msaaGridForDisplay = \u00c7oklu \u00d6rnek Kenar Yumu\u015fatma Izgaras\u0131 (G\u00f6r\u00fcnt\u00fcleme) +config.description.msaaGridForDisplay = G\u00f6r\u00fcnt\u00fcleme amac\u0131yla NxN boyutunda \u00c7oklu \u00d6rnek Kenar Yumu\u015fatma \u0131zgaras\u0131 kullan\u0131n. +config.name.msaaGridForExport = \u00c7oklu \u00d6rnek Kenar Yumu\u015fatma Izgaras\u0131 (D\u0131\u015fa Aktar) +config.description.msaaGridForExport = G\u00f6r\u00fcnt\u00fcleme ama\u00e7l\u0131 NxN boyutunda \u00e7oklu \u00f6rnek kenar yumu\u015fatma \u0131zgaras\u0131. +config.name.useMinimumStrokeWidth1Px = Minimum \u00e7izgi kal\u0131nl\u0131\u011f\u0131 1 piksel (Flash'taki gibi) +config.description.useMinimumStrokeWidth1Px = Minimum \u00e7izgi kal\u0131nl\u0131\u011f\u0131 olarak 1 piksel kullan\u0131n. Flash \u00e7izgileri bu \u015fekilde i\u015fler. Daha ince \u00e7izgiler elde etmek i\u00e7in bunu kapat\u0131n. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/ConvertTextTypeDialog_sl.properties b/src/com/jpexs/decompiler/flash/gui/locales/ConvertTextTypeDialog_sl.properties new file mode 100644 index 000000000..99287a7d6 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/ConvertTextTypeDialog_sl.properties @@ -0,0 +1,6 @@ +dialog.title = Pretvori vrsto besedila +text.DefineText = stati\u010dno besedilo, brez alfa kanala +text.DefineText2 = stati\u010dno besedilo z alfa kanalom +text.DefineEditText = dinami\u010dno ali vhodno besedilo +button.ok = V redu +button.cancel = Prekli\u010di diff --git a/src/com/jpexs/decompiler/flash/gui/locales/ConvertTextTypeDialog_tr.properties b/src/com/jpexs/decompiler/flash/gui/locales/ConvertTextTypeDialog_tr.properties new file mode 100644 index 000000000..de8dc493c --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/ConvertTextTypeDialog_tr.properties @@ -0,0 +1,6 @@ +dialog.title = Metin t\u00fcr\u00fcn\u00fc d\u00f6n\u00fc\u015ft\u00fcr +text.DefineText = statik metin, alfa kanal\u0131 yok +text.DefineText2 = statik metin, alfa kanal\u0131 var +text.DefineEditText = dinamik veya giri\u015f metni +button.ok = Tamam +button.cancel = \u0130ptal diff --git a/src/com/jpexs/decompiler/flash/gui/locales/EasyPanel_tr.properties b/src/com/jpexs/decompiler/flash/gui/locales/EasyPanel_tr.properties index a9ca8b3d6..1cdd29f31 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/EasyPanel_tr.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/EasyPanel_tr.properties @@ -162,3 +162,6 @@ property.instance.filters.glowColor = par\u0131lt\u0131 rengi property.instance.filters.innerGlow = i\u00e7 par\u0131lt\u0131 property.instance.filters.menu.enable = Filtreyi etkinle\u015ftir veya devre d\u0131\u015f\u0131 b\u0131rak property.instance.display.ratio = Oran +#after 24.0.1 +properties.instance.header.text = Metin +action.change.text = Metin diff --git a/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog_sl.properties b/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog_sl.properties index d08d43bcb..019cf7d79 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog_sl.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog_sl.properties @@ -120,3 +120,7 @@ arrow = \ud83e\udc06 frames.apng = APNG sprites.apng = APNG morphshapes.apng = APNG +#after 25.1.3 +buttons.svg_combined = Kombinirani SVG +antialias = Uporabi napredni upodabljalnik MSAA (po\u010dasno) +antialias.hint = Uporabite napredni upodabljalnik z ve\u010dvzor\u010dnim glajenjem robov. Natan\u010dnej\u0161e, vendar po\u010dasnej\u0161e od standardnega upodabljanja. Uporablja se za brezhibno upodabljanje oblik. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog_tr.properties b/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog_tr.properties index 006b930b4..4b6d0749a 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog_tr.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog_tr.properties @@ -12,7 +12,6 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -titleFormat = %title%: shapes = \u015eekiller shapes.svg = SVG shapes.png = PNG @@ -96,3 +95,32 @@ embed = G\u00f6m\u00fcl\u00fc varl\u0131klar\u0131 [Embed] yoluyla d\u0131\u015f #after 20.1.0 resampleWav = Wav'\u0131 44kHz'e yeniden \u00f6rnekle transparentFrameBackground = Arka plan rengini yoksay (saydam yap) +titleFormat = %title%: +shapes.webp = WEBP +images.webp = WEBP +morphshapes.webp_start_end = WEBP (ba\u015flang\u0131\u00e7, biti\u015f) +frames.webp = WEBP +sprites.webp = WEBP +buttons.webp = WEBP +#after 21.1.2 +morphshapes.bmp_frames = BMP (kareler) +morphshapes.png_frames = PNG (kareler) +morphshapes.svg_frames = SVG (kareler) +morphshapes.webp_frames = WEBP (kareler) +morphshapes.avi = AVI +morphshapes.webp = WEBP +frames.webp_animated = WEBP (animasyonlu) +sprites.webp_animated = WEBP (animasyonlu) +morph.duration = \u015eekil de\u011fi\u015ftirme s\u00fcresi +morph.duration.seconds = sn +morph.numberOfFrames = \u015eekil de\u011fi\u015ftirme kare say\u0131s\u0131 +morph.duration.invalid = Ge\u00e7ersiz \u015fekil de\u011fi\u015ftirme s\u00fcresi. Saniye cinsinden pozitif ondal\u0131k say\u0131 girin. +morph.numberOfFrames.invalid = Ge\u00e7ersiz kare say\u0131s\u0131. 2'den b\u00fcy\u00fck veya e\u015fit pozitif tam say\u0131 girin. +arrow = \ud83e\udc06 +frames.apng = APNG +sprites.apng = APNG +morphshapes.apng = APNG +#after 25.1.3 +buttons.svg_combined = SVG birle\u015ftirilmi\u015f +antialias = Geli\u015fmi\u015f MSAA olu\u015fturucu kullan (yava\u015f) +antialias.hint = \u00c7oklu \u00f6rneklemeli kenar yumu\u015fatma \u00f6zelli\u011fine sahip geli\u015fmi\u015f olu\u015fturucu kullan\u0131n. Standart olu\u015fturucudan daha hassas, ancak daha yava\u015f. Kusursuz \u015fekil olu\u015fturma i\u00e7in kullan\u0131n. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/FlaExportDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/FlaExportDialog.properties new file mode 100644 index 000000000..e6f407537 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/FlaExportDialog.properties @@ -0,0 +1,8 @@ +dialog.title = FLA export +button.ok = OK +button.cancel = Cancel + +recommended = (recommended) +version = FLA format version: + +compressed = Compressed \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_sl.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_sl.properties index 9465d6731..4c4846f89 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_sl.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_sl.properties @@ -1088,4 +1088,21 @@ message.info.debugListen = S poslu\u0161anjem lahko izvajate SWF datoteke prek z Nepripravljene datoteke bo razhro\u0161\u010devalnik ignoriral!\n\n\ Nasvet: \u010ce \u017eelite samo razhro\u0161\u010devati SWF v samostojnem razhro\u0161\u010devalniku vsebine,\n\ uporabite namesto tega akcijo "Razhro\u0161\u010devanje", saj bo ta samodejno pripravila SWF.\n\n - +#after 25.1.1 +debug.watch.remove = Odstrani spremljanje +error.debug.watch.remove = Spremljanja te spremenljivke ni mogo\u010de odstraniti. +variables.header.watches = Opazovane spremenljivke +#after 25.1.2 +menu.debugging.debug.stopListening = Prenehaj poslu\u0161ati +menu.debugging.debug.disconnectSession = Prekini sejo +sort.alphabetically = Razvrsti po abecedi +#after 25.1.3 +menu.export.file = Izvozi datoteko v... +filter.slnx = XML re\u0161itve .NET (*.slnx) +menu.file.export.xaml = Izvozi XAML +work.exporting.xaml = Izva\u017eanje XAML +contextmenu.exportXaml = Izvozi XAML +menu.file.import.bulkImport = Mno\u017ei\u010dni uvoz ... +menu.file.import.createTagFromFile = Ustvari oznako iz datoteke... +contextmenu.convertTextType = Pretvori vrsto besedila +button.antialias.hint = Uporabi napredni upodabljalnik z ve\u010dvzor\u010dnim glajenjem (po\u010dasno) diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_tr.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_tr.properties index a78da01f4..982662d02 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_tr.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_tr.properties @@ -1039,7 +1039,7 @@ contextmenu.showInEasy = Basit d\u00fczenleyicide g\u00f6ster work.debugging.start = Flash i\u00e7erik hata ay\u0131klay\u0131c\u0131s\u0131n\u0131 ba\u015flatma menu.file.view.alwaysOnTop = Her zaman \u00fcstte contextmenu.showDetail = Ayr\u0131nt\u0131lar\u0131 g\u00f6ster -highlighter.occurrences = Olu\u015fumlar\u0131 i\u015faretle +highlighter.occurrences = Olaylar\u0131 i\u015faretle highlighter.currentLine = Ge\u00e7erli sat\u0131r highlighter.error = Hata: %error% message.link.clicked = Ba\u015fka bir SWF dosyas\u0131na giden bir ba\u011flant\u0131ya t\u0131klad\u0131n\u0131z. @@ -1061,3 +1061,52 @@ abc.link.dialog.noOtherFilesOpened = Ba\u015fka dosya a\u00e7\u0131lmad\u0131 #after 24.0.1 deobfuscate_options.skip_uninitialized_class_fields_detection = Ba\u015flat\u0131lmam\u0131\u015f s\u0131n\u0131f alanlar\u0131n\u0131n alg\u0131lanmas\u0131n\u0131 atla work.decompiling.allScripts.ucf.canBeSkipped = Bu ad\u0131m\u0131 gizleme se\u00e7eneklerinde (k\u0131rm\u0131z\u0131 \u00e7arp\u0131 i\u015fareti olan simge) kapatabilirsiniz +text.copy = Kopyala +text.selectAll = T\u00fcm\u00fcn\u00fc Se\u00e7 +menu.settings.autoDeobfuscateIdentifiers = Tan\u0131mlay\u0131c\u0131lar\u0131 a\u00e7\u0131\u011fa \u00e7\u0131kar +deobfuscate_options.deobfuscateIdentifiers = Tan\u0131mlay\u0131c\u0131lar\u0131 a\u00e7\u0131\u011fa \u00e7\u0131kar +node.unknown = bilinmeyen +node.errored = hatal\u0131 +filter.swf_spl_swt = SWF dosyalar\u0131 (*.swf, *.spl, *.swt) +filter.swt = Olu\u015fturucu \u015fablonlar\u0131 (*.swt) +contextmenu.normalizeFonts = Yaz\u0131 tiplerini normalle\u015ftir +#after 24.1.1 +contextmenu.saveSwc = Swc olarak kaydet... +work.generating.swc = Swc olu\u015fturuluyor... +#after 25.0.0 +menu.file.start.debuglisten = Hata ay\u0131klama dinleniyor... +work.debugging.listening = Gelen ba\u011flant\u0131lar\u0131 dinleniyor... +contextmenu.prepareDebug.injectDebug = Hata ay\u0131klama i\u00e7in dosyay\u0131 haz\u0131rla (+ hata ay\u0131klama bilgisi ekle) +contextmenu.prepareDebug.injectDebug.pcode = P-kodu hata ay\u0131klama i\u00e7in dosyay\u0131 haz\u0131rla (+ hata ay\u0131klama bilgisi ekle) +contextmenu.prepareDebug.generateSwd = Hata ay\u0131klama i\u00e7in dosyay\u0131 haz\u0131rla (+ SWD olu\u015ftur) +contextmenu.prepareDebug.generateSwd.pcode = P-kodu hata ay\u0131klama i\u00e7in dosyay\u0131 haz\u0131rla (+ SWD olu\u015ftur) +prepareDebug.title = Haz\u0131rlanan s\u00fcr\u00fcm\u00fc kaydet +work.prepareDebug = Hata ay\u0131klama i\u00e7in dosya haz\u0131rlan\u0131yor... +prepareDebug.finishedin = %time% s\u00fcrede haz\u0131rland\u0131 +work.halted.with = %file% dosyas\u0131n\u0131n hata ay\u0131klamas\u0131 ba\u015flat\u0131ld\u0131, y\u00fcr\u00fctme durduruldu. Kesme noktalar\u0131 ekleyin ve \u00c7al\u0131\u015ft\u0131rmaya Devam Et (F5) d\u00fc\u011fmesine t\u0131klayarak \u00e7al\u0131\u015fmaya devam edin. +debug.session = Oturum %id% +debug.session.running = (\u00c7al\u0131\u015f\u0131yor) +message.info.debugListen = Dinleme eylemi, harici hata ay\u0131klama oynat\u0131c\u0131s\u0131 ve \u00f6rne\u011fin web taray\u0131c\u0131s\u0131 hata ay\u0131klama eklentileri arac\u0131l\u0131\u011f\u0131yla SWF dosyalar\u0131n\u0131 \u00e7al\u0131\u015ft\u0131rman\u0131za olanak tan\u0131r.\n\n \ + Bunun \u00e7al\u0131\u015fmas\u0131 i\u00e7in, hata ay\u0131klamak istedi\u011finiz t\u00fcm dosyalar\u0131n \u00f6nce hata ay\u0131klamaya haz\u0131rlanmas\u0131 gerekir.\n \ + SWF dosyalar\u0131n\u0131 ba\u011flam men\u00fcs\u00fc eylemi "Dosyay\u0131 hata ay\u0131klamaya haz\u0131rla" ile haz\u0131rlayabilirsiniz.\n \ + Haz\u0131rlanmam\u0131\u015f dosyalar hata ay\u0131klay\u0131c\u0131 taraf\u0131ndan g\u00f6z ard\u0131 edilecektir!\n\n \ + \u0130pucu: Yaln\u0131zca ba\u011f\u0131ms\u0131z i\u00e7erik hata ay\u0131klay\u0131c\u0131s\u0131nda SWF'de hata ay\u0131klamak istiyorsan\u0131z, \n \ + bunun yerine "Hata Ay\u0131klama" eylemini kullan\u0131n, \u00e7\u00fcnk\u00fc bu SWF'yi otomatik olarak haz\u0131rlayacakt\u0131r.\n\n +#after 25.1.1 +debug.watch.remove = \u0130zlemeyi Kald\u0131r +error.debug.watch.remove = Bu de\u011fi\u015fkenden izleme kald\u0131r\u0131lamaz. +variables.header.watches = \u0130zlemeler +#after 25.1.2 +menu.debugging.debug.stopListening = Dinlemeyi durdur +menu.debugging.debug.disconnectSession = Oturumu sonland\u0131r +sort.alphabetically = Alfabetik olarak s\u0131rala +#after 25.1.3 +menu.export.file = Dosyay\u0131 \u015furaya d\u0131\u015fa aktar... +filter.slnx = .NET \u00e7\u00f6z\u00fcm\u00fc XML (*.slnx) +menu.file.export.xaml = XAML'yi d\u0131\u015fa aktar +work.exporting.xaml = XAML d\u0131\u015fa aktar\u0131l\u0131yor +contextmenu.exportXaml = XAML'yi d\u0131\u015fa aktar +menu.file.import.bulkImport = Toplu i\u00e7e aktarma... +menu.file.import.createTagFromFile = Dosyadan etiket olu\u015ftur... +contextmenu.convertTextType = Metin t\u00fcr\u00fcn\u00fc d\u00f6n\u00fc\u015ft\u00fcr +button.antialias.hint = \u00c7oklu \u00f6rnek kenar yumu\u015fatma ile geli\u015fmi\u015f olu\u015fturucu kullan (yava\u015f) diff --git a/src/com/jpexs/decompiler/flash/gui/locales/XmlExportDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/XmlExportDialog.properties new file mode 100644 index 000000000..2b25421ff --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/XmlExportDialog.properties @@ -0,0 +1,12 @@ +dialog.title = Export XML +button.ok = OK +button.cancel = Cancel + +selectExternal = Select items which will be available externally: + +all = Select all +none = Select none + +as12scripts = AS1/2 scripts +defineSound = DefineSounds +xml = XML (no external) \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/XmlExportDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/XmlExportDialog_cs.properties new file mode 100644 index 000000000..b073cdf45 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/XmlExportDialog_cs.properties @@ -0,0 +1,12 @@ +dialog.title = Exportovat XML +button.ok = OK +button.cancel = Storno + +selectExternal = Vyberte polo\u017eky, kter\u00e9 budou dostupn\u00e9 extern\u011b: + +all = Vybrat v\u0161e +none = Nevybrat nic + +as12scripts = AS1/2 skripty +defineSound = DefineSounds +xml = XML (ne extern\u00ed) \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/XmlExportDialog_de.properties b/src/com/jpexs/decompiler/flash/gui/locales/XmlExportDialog_de.properties new file mode 100644 index 000000000..17e315ed1 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/XmlExportDialog_de.properties @@ -0,0 +1,12 @@ +dialog.title = XML exportieren +button.ok = OK +button.cancel = Abbrechen + +selectExternal = W\u00e4hlen Sie die Elemente aus, die extern verf\u00fcgbar sein sollen: + +all = Alles ausw\u00e4hlen +none = Nichts ausw\u00e4hlen + +as12scripts = AS1/2-Skripte +defineSound = DefineSounds +xml = XML (nicht extern) \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/XmlExportDialog_sk.properties b/src/com/jpexs/decompiler/flash/gui/locales/XmlExportDialog_sk.properties new file mode 100644 index 000000000..6ba90b92a --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/XmlExportDialog_sk.properties @@ -0,0 +1,12 @@ +dialog.title = Exportova\u0165 XML +button.ok = OK +button.cancel = Zru\u0161i\u0165 + +selectExternal = Vyberte polo\u017eky, ktor\u00e9 bud\u00fa dostupn\u00e9 externe: + +all = Vybra\u0165 v\u0161etko +none = Nevybra\u0165 ni\u010d + +as12scripts = AS1/2 skripty +defineSound = DefineSounds +xml = XML (nie extern\u00e9) \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/translator/Translator.java b/src/com/jpexs/decompiler/flash/gui/translator/Translator.java index 9c98ad248..f9b1c25be 100644 --- a/src/com/jpexs/decompiler/flash/gui/translator/Translator.java +++ b/src/com/jpexs/decompiler/flash/gui/translator/Translator.java @@ -74,6 +74,7 @@ import java.util.zip.ZipOutputStream; import javax.swing.AbstractCellEditor; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JFrame; @@ -118,6 +119,9 @@ public class Translator extends JFrame implements ItemListener { private JComboBox localeComboBox; private JComboBox resourcesComboBox; + private boolean autosaveOnExit = true; + private JCheckBox autosaveCheckBox; + private String lastSaveDir = ""; private static final String DO_NOT_EDIT = "!!!! FFDec translators - please do not edit anything below this line !!!"; @@ -318,7 +322,9 @@ public class Translator extends JFrame implements ItemListener { @Override public void windowClosing(WindowEvent e) { try { - save(); + if (autosaveOnExit) { + save(); + } saveWindow(); } catch (IOException ex) { Logger.getLogger(Translator.class.getName()).log(Level.SEVERE, null, ex); @@ -729,11 +735,24 @@ public class Translator extends JFrame implements ItemListener { } } }); + + autosaveCheckBox = new JCheckBox("Autosave on exit", true); + autosaveCheckBox.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + autosaveOnExit = autosaveCheckBox.isSelected(); + } + }); + buttonsPanel.add(importButton); buttonsPanel.add(exportButton); buttonsPanel.add(startOverButton); - cnt.add(buttonsPanel, BorderLayout.SOUTH); + JPanel bottomPanel = new JPanel(new BorderLayout()); + bottomPanel.add(buttonsPanel, BorderLayout.CENTER); + bottomPanel.add(autosaveCheckBox, BorderLayout.EAST); + + cnt.add(bottomPanel, BorderLayout.SOUTH); cnt.add(new JScrollPane(table), BorderLayout.CENTER); resizeColumnWidth(table); @@ -1108,6 +1127,10 @@ public class Translator extends JFrame implements ItemListener { case "export.dir": lastSaveDir = value; break; + case "autosave": + autosaveOnExit = value.equals("true"); + autosaveCheckBox.setSelected(autosaveOnExit); + break; } } @@ -1133,6 +1156,7 @@ public class Translator extends JFrame implements ItemListener { pw.println("column.en.width=" + table.getColumn("en").getWidth()); pw.println("column.translated.width=" + table.getColumn("translated").getWidth()); pw.println("export.dir=" + lastSaveDir); + pw.println("autosave=" + autosaveOnExit); writer.close(); }