perf: optimize recursion, avoid stackoverflow on larger scripts (#2672)

This commit is contained in:
Jindra Petřík
2026-03-20 07:56:39 +01:00
parent cd8a9dbdad
commit 2bc1c4e012
24 changed files with 31249 additions and 623 deletions

View File

@@ -0,0 +1,71 @@
/*
* 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;
import com.jpexs.decompiler.flash.action.Action;
import com.jpexs.decompiler.flash.action.as2.Trait;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.helpers.CodeFormatting;
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
import com.jpexs.decompiler.flash.helpers.StringBuilderTextWriter;
import com.jpexs.decompiler.flash.tags.DoActionTag;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.testng.Assert.fail;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
*
* @author JPEXS
*/
public class ActionScript2LongTest extends ActionScript2TestBase {
@BeforeClass
public void init() throws IOException, InterruptedException {
//Main.initLogging(false);
Configuration.autoDeobfuscate.set(false);
Configuration.showAllAddresses.set(false);
Configuration.pluginPath.set(null);
swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/as2_long/as2_long.swf")), false);
}
@Test
public void testLongScript() {
StringBuilder sb = new StringBuilder();
StringBuilderTextWriter writer = new StringBuilderTextWriter(new CodeFormatting(), sb);
DoActionTag doa = getFirstActionTag();
try {
Action.actionsToSource(new HashMap<>(),doa, doa.getActions(), "", writer, "UTF-8");
} catch (InterruptedException ex) {
fail();
}
String result = sb.toString();
if (result.contains("/*")) {
fail();
}
if (!result.contains("\"9999\"")) {
fail();
}
}
}

View File

@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.abc.types.ConvertData;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.CodeFormatting;
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
import com.jpexs.decompiler.flash.helpers.StringBuilderTextWriter;
import com.jpexs.decompiler.flash.tags.DoABC2Tag;
import com.jpexs.decompiler.flash.tags.Tag;
import java.io.IOException;
@@ -46,6 +47,7 @@ public class ActionScript3ClassTest extends ActionScript3DecompileTestBase {
addSwf("assembled", "testdata/as3_assembled/bin/as3_assembled.swf");
addSwf("getouterscope", "testdata/getouterscope/getouterscope.swf");
addSwf("haxe", "testdata/haxe/output.swf");
addSwf("long", "testdata/as3_long/bin/as3_long.flex.swf");
}
private void decompileScriptPack(String swfId, String path, String expectedResult) {
@@ -790,4 +792,40 @@ public class ActionScript3ClassTest extends ActionScript3DecompileTestBase {
+ "}\n"
+ "}");
}
@Test
public void testLongScript() {
DoABC2Tag tag = null;
ABC abc = null;
ScriptPack scriptPack = null;
SWF swf = getSwf("long");
for (Tag t : swf.getTags()) {
if (t instanceof DoABC2Tag) {
tag = (DoABC2Tag) t;
abc = tag.getABC();
scriptPack = abc.findScriptPackByPath("tests.TestLongScript", Arrays.asList(abc));
if (scriptPack != null) {
break;
}
}
}
assertNotNull(abc);
assertNotNull(scriptPack);
StringBuilderTextWriter writer = null;
StringBuilder sb = new StringBuilder();
try {
writer = new StringBuilderTextWriter(new CodeFormatting(), sb);
scriptPack.toSource(swf.getAbcIndex(), writer, abc.script_info.get(scriptPack.scriptIndex).traits.traits, new ConvertData(), ScriptExportMode.AS, false, false, false);
} catch (InterruptedException ex) {
fail();
}
String result = sb.toString();
if (result.contains("/*")) {
fail();
}
if (!result.contains("\"9999\"")) {
fail();
}
}
}