mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-26 06:50:51 +00:00
Added Optimize ABC action (remove unused items) - available through ABC Explorer
Fixed Outputstreams position calculation (ABCOutputStream, ...)
This commit is contained in:
@@ -145,6 +145,13 @@ public class SWFOutputStream extends OutputStream {
|
||||
pos += b.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
alignByte();
|
||||
os.write(b, off, len);
|
||||
pos += len;
|
||||
}
|
||||
|
||||
public void write(ByteArrayRange b) throws IOException {
|
||||
alignByte();
|
||||
os.write(b.getArray(), b.getPos(), b.getLength());
|
||||
|
||||
@@ -63,6 +63,7 @@ import com.jpexs.decompiler.flash.treeitems.Openable;
|
||||
import com.jpexs.decompiler.flash.treeitems.OpenableList;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.utf8.Utf8PrintWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -1161,8 +1162,7 @@ public class ABC implements Openable {
|
||||
for (int i = 0; i < bodies.size(); i++) {
|
||||
output.println("MethodBody[" + i + "]:"); //+ bodies[i].toString(this, constants, method_info));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<MultinameUsage> findMultinameDefinition(int multinameIndex) {
|
||||
List<MultinameUsage> usages = findMultinameUsage(multinameIndex, false);
|
||||
@@ -1184,7 +1184,7 @@ public class ABC implements Openable {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public List<MultinameUsage> findMultinameUsage(int multinameIndex, boolean exactMatch) {
|
||||
MultinameUsageDetector det = new MultinameUsageDetector();
|
||||
List<Usage> retUsage = det.findMultinameUsage(this, multinameIndex, exactMatch);
|
||||
@@ -1270,8 +1270,6 @@ public class ABC implements Openable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int findMethodInfoByName(int classId, String methodNameWithSuffix) {
|
||||
if (classId > -1) {
|
||||
for (Trait t : instance_info.get(classId).instance_traits.traits) {
|
||||
@@ -1728,10 +1726,7 @@ public class ABC implements Openable {
|
||||
s--;
|
||||
}
|
||||
}
|
||||
getSwf().clearAbcListCache();
|
||||
getSwf().clearScriptCache();
|
||||
getMethodIndexing();
|
||||
getSwf().getAbcIndex().refreshAbc(this);
|
||||
clearAllCaches();
|
||||
|
||||
fireChanged();
|
||||
}
|
||||
@@ -2275,5 +2270,13 @@ public class ABC implements Openable {
|
||||
|
||||
public long getDataSize() {
|
||||
return dataSize;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearAllCaches() {
|
||||
resetMethodIndexing();
|
||||
getSwf().clearAbcListCache();
|
||||
getSwf().clearScriptCache();
|
||||
getMethodIndexing();
|
||||
getSwf().getAbcIndex().refreshAbc(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class ABCOutputStream extends OutputStream {
|
||||
|
||||
private final OutputStream os;
|
||||
private long position = 0L;
|
||||
|
||||
|
||||
public ABCOutputStream(OutputStream os) {
|
||||
this.os = os;
|
||||
}
|
||||
@@ -57,13 +57,13 @@ public class ABCOutputStream extends OutputStream {
|
||||
|
||||
@Override
|
||||
public void write(byte[] data) throws IOException {
|
||||
super.write(data);
|
||||
position += data.length;
|
||||
os.write(data);
|
||||
position += data.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
super.write(b, off, len);
|
||||
os.write(b, off, len);
|
||||
position += len;
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -161,8 +161,10 @@ public final class AbcIndexing {
|
||||
Integer builtInNs = builtInNsPerAbc.get(abc);
|
||||
|
||||
if (builtInNs == null) {
|
||||
builtInIndex = abc.constants.getNamespaceId(Namespace.KIND_NAMESPACE, BUILT_IN_NS, 0, true);
|
||||
builtInNsPerAbc.put(abc, builtInIndex);
|
||||
//we need to avoid modifying the ABC
|
||||
/* builtInIndex = abc.constants.getNamespaceId(Namespace.KIND_NAMESPACE, BUILT_IN_NS, 0, true);
|
||||
builtInNsPerAbc.put(abc, builtInIndex);*/
|
||||
builtInIndex = Integer.MIN_VALUE; //??
|
||||
} else {
|
||||
builtInIndex = builtInNs;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2023 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.usages.simple;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ABCOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.types.ClassInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.MetadataInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.abc.types.Namespace;
|
||||
import com.jpexs.decompiler.flash.abc.types.NamespaceSet;
|
||||
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.ValueKind;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitClass;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.helpers.NulStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ABCOptimizer {
|
||||
|
||||
public void optimize(ABC abc) {
|
||||
ABCSimpleUsageDetector usageDetector = new ABCSimpleUsageDetector(abc);
|
||||
usageDetector.detect();
|
||||
Map<ABCSimpleUsageDetector.ItemKind, List<List<String>>> usages = usageDetector.getUsages();
|
||||
Map<ABCSimpleUsageDetector.ItemKind, List<Integer>> notReferencedIndices = new HashMap<>();
|
||||
Map<ABCSimpleUsageDetector.ItemKind, Map<Integer, Integer>> replaceMap = new HashMap<>();
|
||||
|
||||
for (ABCSimpleUsageDetector.ItemKind kind : usages.keySet()) {
|
||||
List<List<String>> usagesList = usages.get(kind);
|
||||
notReferencedIndices.put(kind, new ArrayList<>());
|
||||
replaceMap.put(kind, new HashMap<>());
|
||||
if (kind.hasReservedZeroIndex()) {
|
||||
replaceMap.get(kind).put(0, 0);
|
||||
}
|
||||
int pos = kind.hasReservedZeroIndex() ? 1 : 0;
|
||||
for (int i = pos; i < usagesList.size(); i++) {
|
||||
if (usagesList.get(i).isEmpty()) {
|
||||
notReferencedIndices.get(kind).add(i);
|
||||
} else {
|
||||
replaceMap.get(kind).put(i, pos);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
for (ABCSimpleUsageDetector.ItemKind kind : replaceMap.keySet()) {
|
||||
System.err.println("---------");
|
||||
System.err.println("" + kind + " map:");
|
||||
for (int key : replaceMap.get(kind).keySet()) {
|
||||
System.err.println(" " + key + " => " + replaceMap.get(kind).get(key));
|
||||
}
|
||||
System.err.println(" " + kind + " not referenced:");
|
||||
for (int key : notReferencedIndices.get(kind)) {
|
||||
System.err.println(" " + key);
|
||||
}
|
||||
}
|
||||
System.err.println("==================="); */
|
||||
|
||||
for (int i = 0; i < abc.script_info.size(); i++) {
|
||||
ScriptInfo m = abc.script_info.get(i);
|
||||
m.init_index = handleReplace(ABCSimpleUsageDetector.ItemKind.METHODINFO, m.init_index, replaceMap);
|
||||
walkTraits(abc, m.traits, replaceMap);
|
||||
}
|
||||
|
||||
for (int i = 0; i < abc.method_info.size(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.METHODINFO).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
MethodInfo m = abc.method_info.get(i);
|
||||
m.name_index = handleReplace(ABCSimpleUsageDetector.ItemKind.STRING, m.name_index, replaceMap);
|
||||
if (m.flagHas_paramnames()) {
|
||||
for (int j = 0; j < m.paramNames.length; j++) {
|
||||
m.paramNames[j] = handleReplace(ABCSimpleUsageDetector.ItemKind.STRING, m.paramNames[j], replaceMap);
|
||||
}
|
||||
}
|
||||
if (m.flagHas_optional()) {
|
||||
for (int j = 0; j < m.optional.length; j++) {
|
||||
m.optional[j].value_index = handleReplaceValueKind(m.optional[j].value_kind, m.optional[j].value_index, replaceMap);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < m.param_types.length; j++) {
|
||||
m.param_types[j] = handleReplace(ABCSimpleUsageDetector.ItemKind.MULTINAME, m.param_types[j], replaceMap);
|
||||
}
|
||||
|
||||
m.ret_type = handleReplace(ABCSimpleUsageDetector.ItemKind.MULTINAME, m.ret_type, replaceMap);
|
||||
}
|
||||
|
||||
for (int i = 0; i < abc.metadata_info.size(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.METADATAINFO).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
MetadataInfo m = abc.metadata_info.get(i);
|
||||
m.name_index = handleReplace(ABCSimpleUsageDetector.ItemKind.STRING, m.name_index, replaceMap);
|
||||
for (int j = 0; j < m.keys.length; j++) {
|
||||
m.keys[j] = handleReplace(ABCSimpleUsageDetector.ItemKind.STRING, m.keys[j], replaceMap);
|
||||
}
|
||||
for (int j = 0; j < m.values.length; j++) {
|
||||
m.values[j] = handleReplace(ABCSimpleUsageDetector.ItemKind.STRING, m.values[j], replaceMap);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < abc.constants.getMultinameCount(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.MULTINAME).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
Multiname m = abc.constants.getMultiname(i);
|
||||
if (m.hasOwnName()) {
|
||||
m.name_index = handleReplace(ABCSimpleUsageDetector.ItemKind.STRING, m.name_index, replaceMap);
|
||||
}
|
||||
if (m.hasOwnNamespace()) {
|
||||
m.namespace_index = handleReplace(ABCSimpleUsageDetector.ItemKind.NAMESPACE, m.namespace_index, replaceMap);
|
||||
}
|
||||
if (m.hasOwnNamespaceSet()) {
|
||||
m.namespace_set_index = handleReplace(ABCSimpleUsageDetector.ItemKind.NAMESPACESET, m.namespace_set_index, replaceMap);
|
||||
}
|
||||
if (m.kind == Multiname.TYPENAME) {
|
||||
m.qname_index = handleReplace(ABCSimpleUsageDetector.ItemKind.MULTINAME, m.qname_index, replaceMap);
|
||||
for (int j = 0; j < m.params.length; j++) {
|
||||
m.params[j] = handleReplace(ABCSimpleUsageDetector.ItemKind.MULTINAME, m.params[j], replaceMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < abc.constants.getNamespaceCount(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.NAMESPACE).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
Namespace m = abc.constants.getNamespace(i);
|
||||
m.name_index = handleReplace(ABCSimpleUsageDetector.ItemKind.STRING, m.name_index, replaceMap);
|
||||
}
|
||||
|
||||
for (int i = 1; i < abc.constants.getNamespaceSetCount(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.MULTINAME).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
NamespaceSet m = abc.constants.getNamespaceSet(i);
|
||||
for (int j = 0; j < m.namespaces.length; j++) {
|
||||
m.namespaces[j] = handleReplace(ABCSimpleUsageDetector.ItemKind.NAMESPACE, m.namespaces[j], replaceMap);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < abc.bodies.size(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.METHODBODY).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
MethodBody m = abc.bodies.get(i);
|
||||
for (int j = 0; j < m.exceptions.length; j++) {
|
||||
m.exceptions[j].name_index = handleReplace(ABCSimpleUsageDetector.ItemKind.MULTINAME, m.exceptions[j].name_index, replaceMap);
|
||||
m.exceptions[j].type_index = handleReplace(ABCSimpleUsageDetector.ItemKind.MULTINAME, m.exceptions[j].type_index, replaceMap);
|
||||
}
|
||||
m.method_info = handleReplace(ABCSimpleUsageDetector.ItemKind.METHODINFO, m.method_info, replaceMap);
|
||||
walkTraits(abc, m.traits, replaceMap);
|
||||
AVM2Code acode = m.getCode();
|
||||
List<AVM2Instruction> code = acode.code;
|
||||
boolean bodyModified = false;
|
||||
for (int ip = 0; ip < code.size(); ip++) {
|
||||
AVM2Instruction ins = code.get(ip);
|
||||
for (int operandIndex = 0; operandIndex < ins.definition.operands.length; operandIndex++) {
|
||||
int oldOperand = ins.operands[operandIndex];
|
||||
switch (ins.definition.operands[operandIndex]) {
|
||||
case AVM2Code.DAT_CLASS_INDEX:
|
||||
ins.operands[operandIndex] = handleReplace(ABCSimpleUsageDetector.ItemKind.CLASS, ins.operands[operandIndex], replaceMap);
|
||||
break;
|
||||
case AVM2Code.DAT_DOUBLE_INDEX:
|
||||
ins.operands[operandIndex] = handleReplace(ABCSimpleUsageDetector.ItemKind.DOUBLE, ins.operands[operandIndex], replaceMap);
|
||||
break;
|
||||
case AVM2Code.DAT_INT_INDEX:
|
||||
ins.operands[operandIndex] = handleReplace(ABCSimpleUsageDetector.ItemKind.INT, ins.operands[operandIndex], replaceMap);
|
||||
break;
|
||||
case AVM2Code.DAT_METHOD_INDEX:
|
||||
ins.operands[operandIndex] = handleReplace(ABCSimpleUsageDetector.ItemKind.METHODINFO, ins.operands[operandIndex], replaceMap);
|
||||
break;
|
||||
case AVM2Code.DAT_MULTINAME_INDEX:
|
||||
ins.operands[operandIndex] = handleReplace(ABCSimpleUsageDetector.ItemKind.MULTINAME, ins.operands[operandIndex], replaceMap);
|
||||
break;
|
||||
case AVM2Code.DAT_NAMESPACE_INDEX:
|
||||
ins.operands[operandIndex] = handleReplace(ABCSimpleUsageDetector.ItemKind.NAMESPACE, ins.operands[operandIndex], replaceMap);
|
||||
break;
|
||||
case AVM2Code.DAT_STRING_INDEX:
|
||||
ins.operands[operandIndex] = handleReplace(ABCSimpleUsageDetector.ItemKind.STRING, ins.operands[operandIndex], replaceMap);
|
||||
break;
|
||||
case AVM2Code.DAT_UINT_INDEX:
|
||||
ins.operands[operandIndex] = handleReplace(ABCSimpleUsageDetector.ItemKind.UINT, ins.operands[operandIndex], replaceMap);
|
||||
break;
|
||||
}
|
||||
int newOperand = ins.operands[operandIndex];
|
||||
if (oldOperand != newOperand) {
|
||||
bodyModified = true;
|
||||
int byteDelta = ABCOutputStream.getU30ByteLength(newOperand) - ABCOutputStream.getU30ByteLength(oldOperand);
|
||||
if (byteDelta != 0) {
|
||||
acode.updateInstructionByteCount(ip, byteDelta, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bodyModified) {
|
||||
m.setModified();
|
||||
}
|
||||
}
|
||||
|
||||
AVM2ConstantPool newCpool = new AVM2ConstantPool();
|
||||
for (int i = 1; i < abc.constants.getIntCount(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.INT).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
newCpool.addInt(abc.constants.getInt(i));
|
||||
}
|
||||
for (int i = 1; i < abc.constants.getUIntCount(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.UINT).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
newCpool.addUInt(abc.constants.getUInt(i));
|
||||
}
|
||||
for (int i = 1; i < abc.constants.getDoubleCount(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.DOUBLE).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
newCpool.addDouble(abc.constants.getDouble(i));
|
||||
}
|
||||
|
||||
for (int i = 1; i < abc.constants.getStringCount(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.STRING).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
newCpool.addString(abc.constants.getString(i));
|
||||
}
|
||||
|
||||
for (int i = 1; i < abc.constants.getNamespaceCount(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.NAMESPACE).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
newCpool.addNamespace(abc.constants.getNamespace(i));
|
||||
}
|
||||
|
||||
for (int i = 1; i < abc.constants.getNamespaceSetCount(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.NAMESPACESET).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
newCpool.addNamespaceSet(abc.constants.getNamespaceSet(i));
|
||||
}
|
||||
|
||||
for (int i = 1; i < abc.constants.getMultinameCount(); i++) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.MULTINAME).contains(i)) {
|
||||
continue;
|
||||
}
|
||||
newCpool.addMultiname(abc.constants.getMultiname(i));
|
||||
}
|
||||
abc.constants = newCpool;
|
||||
|
||||
for (int i = abc.metadata_info.size() - 1; i >= 0; i--) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.METADATAINFO).contains(i)) {
|
||||
abc.metadata_info.remove(i);
|
||||
}
|
||||
}
|
||||
for (int i = abc.bodies.size() - 1; i >= 0; i--) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.METHODBODY).contains(i)) {
|
||||
abc.bodies.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = abc.method_info.size() - 1; i >= 0; i--) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.METHODINFO).contains(i)) {
|
||||
abc.method_info.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = abc.instance_info.size() - 1; i >= 0; i--) {
|
||||
if (notReferencedIndices.get(ABCSimpleUsageDetector.ItemKind.CLASS).contains(i)) {
|
||||
abc.instance_info.remove(i);
|
||||
abc.class_info.remove(i);
|
||||
}
|
||||
}
|
||||
abc.clearAllCaches();
|
||||
try {
|
||||
abc.saveToStream(new NulStream()); //To recalculate dataSize
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
if (abc.parentTag != null) {
|
||||
((Tag) abc.parentTag).setModified(true);
|
||||
}
|
||||
abc.fireChanged();
|
||||
}
|
||||
|
||||
private int handleReplace(ABCSimpleUsageDetector.ItemKind kind, int index, Map<ABCSimpleUsageDetector.ItemKind, Map<Integer, Integer>> replaceMap) {
|
||||
if (!replaceMap.get(kind).containsKey(index)) {
|
||||
return index;
|
||||
}
|
||||
return replaceMap.get(kind).get(index);
|
||||
}
|
||||
|
||||
private int handleReplaceValueKind(int value_kind, int value_index, Map<ABCSimpleUsageDetector.ItemKind, Map<Integer, Integer>> replaceMap) {
|
||||
switch (value_kind) {
|
||||
case ValueKind.CONSTANT_Int:
|
||||
return handleReplace(ABCSimpleUsageDetector.ItemKind.INT, value_index, replaceMap);
|
||||
case ValueKind.CONSTANT_UInt:
|
||||
return handleReplace(ABCSimpleUsageDetector.ItemKind.UINT, value_index, replaceMap);
|
||||
case ValueKind.CONSTANT_Double:
|
||||
return handleReplace(ABCSimpleUsageDetector.ItemKind.DOUBLE, value_index, replaceMap);
|
||||
case ValueKind.CONSTANT_Utf8:
|
||||
return handleReplace(ABCSimpleUsageDetector.ItemKind.STRING, value_index, replaceMap);
|
||||
case ValueKind.CONSTANT_Namespace:
|
||||
case ValueKind.CONSTANT_PackageNamespace:
|
||||
case ValueKind.CONSTANT_PackageInternalNs:
|
||||
case ValueKind.CONSTANT_ProtectedNamespace:
|
||||
case ValueKind.CONSTANT_ExplicitNamespace:
|
||||
case ValueKind.CONSTANT_StaticProtectedNs:
|
||||
case ValueKind.CONSTANT_PrivateNs:
|
||||
return handleReplace(ABCSimpleUsageDetector.ItemKind.NAMESPACE, value_index, replaceMap);
|
||||
}
|
||||
return value_index;
|
||||
}
|
||||
|
||||
private void walkTraits(ABC abc, Traits traits, Map<ABCSimpleUsageDetector.ItemKind, Map<Integer, Integer>> replaceMap) {
|
||||
for (Trait t : traits.traits) {
|
||||
if ((t.kindFlags & Trait.ATTR_Metadata) > 0) {
|
||||
for (int i = 0; i < t.metadata.length; i++) {
|
||||
t.metadata[i] = handleReplace(ABCSimpleUsageDetector.ItemKind.METADATAINFO, t.metadata[i], replaceMap);
|
||||
}
|
||||
}
|
||||
t.name_index = handleReplace(ABCSimpleUsageDetector.ItemKind.MULTINAME, t.name_index, replaceMap);
|
||||
if (t instanceof TraitMethodGetterSetter) {
|
||||
TraitMethodGetterSetter tmgs = (TraitMethodGetterSetter) t;
|
||||
tmgs.method_info = handleReplace(ABCSimpleUsageDetector.ItemKind.METHODINFO, tmgs.method_info, replaceMap);
|
||||
}
|
||||
if (t instanceof TraitFunction) {
|
||||
TraitFunction tf = (TraitFunction) t;
|
||||
tf.method_info = handleReplace(ABCSimpleUsageDetector.ItemKind.METHODINFO, tf.method_info, replaceMap);
|
||||
}
|
||||
if (t instanceof TraitSlotConst) {
|
||||
TraitSlotConst tsc = (TraitSlotConst) t;
|
||||
tsc.type_index = handleReplace(ABCSimpleUsageDetector.ItemKind.MULTINAME, tsc.type_index, replaceMap);
|
||||
tsc.value_index = handleReplaceValueKind(tsc.value_kind, tsc.value_index, replaceMap);
|
||||
}
|
||||
if (t instanceof TraitClass) {
|
||||
TraitClass tc = (TraitClass) t;
|
||||
int classIndex = tc.class_info;
|
||||
InstanceInfo ii = abc.instance_info.get(classIndex);
|
||||
if ((ii.flags & InstanceInfo.CLASS_PROTECTEDNS) != 0) {
|
||||
ii.protectedNS = handleReplace(ABCSimpleUsageDetector.ItemKind.NAMESPACE, ii.protectedNS, replaceMap);
|
||||
}
|
||||
ii.name_index = handleReplace(ABCSimpleUsageDetector.ItemKind.MULTINAME, ii.name_index, replaceMap);
|
||||
ii.super_index = handleReplace(ABCSimpleUsageDetector.ItemKind.MULTINAME, ii.super_index, replaceMap);
|
||||
for (int i = 0; i < ii.interfaces.length; i++) {
|
||||
ii.interfaces[i] = handleReplace(ABCSimpleUsageDetector.ItemKind.MULTINAME, ii.interfaces[i], replaceMap);
|
||||
}
|
||||
ii.iinit_index = handleReplace(ABCSimpleUsageDetector.ItemKind.METHODINFO, ii.iinit_index, replaceMap);
|
||||
walkTraits(abc, ii.instance_traits, replaceMap);
|
||||
|
||||
ClassInfo ci = abc.class_info.get(classIndex);
|
||||
ci.cinit_index = handleReplace(ABCSimpleUsageDetector.ItemKind.METHODINFO, ci.cinit_index, replaceMap);
|
||||
walkTraits(abc, ci.static_traits, replaceMap);
|
||||
|
||||
tc.class_info = handleReplace(ABCSimpleUsageDetector.ItemKind.CLASS, tc.class_info, replaceMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+67
-25
@@ -46,29 +46,41 @@ import java.util.Stack;
|
||||
public class ABCSimpleUsageDetector {
|
||||
|
||||
public static enum ItemKind {
|
||||
INT,
|
||||
UINT,
|
||||
DOUBLE,
|
||||
STRING,
|
||||
NAMESPACE,
|
||||
NAMESPACESET,
|
||||
MULTINAME,
|
||||
METADATAINFO,
|
||||
METHODINFO,
|
||||
METHODBODY,
|
||||
CLASS
|
||||
INT(true),
|
||||
UINT(true),
|
||||
DOUBLE(true),
|
||||
STRING(true),
|
||||
NAMESPACE(true),
|
||||
NAMESPACESET(true),
|
||||
MULTINAME(true),
|
||||
METADATAINFO(false),
|
||||
METHODINFO(false),
|
||||
METHODBODY(false),
|
||||
CLASS(false);
|
||||
|
||||
private boolean reserveZeroIndex;
|
||||
|
||||
private ItemKind (boolean reserveZeroIndex) {
|
||||
this.reserveZeroIndex = reserveZeroIndex;
|
||||
}
|
||||
|
||||
public boolean hasReservedZeroIndex() {
|
||||
return reserveZeroIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<ItemKind, List<List<String>>> usages = new HashMap<>();
|
||||
private final Map<ItemKind, List<List<String>>> usages = new HashMap<>();
|
||||
private final Map<ItemKind, List<Integer>> zeroUsages = new HashMap<>();
|
||||
|
||||
|
||||
private final ABC abc;
|
||||
public ABCSimpleUsageDetector(ABC abc) {
|
||||
this.abc = abc;
|
||||
}
|
||||
|
||||
private void initUsages(ItemKind kind, int itemCount, boolean atleastOne) {
|
||||
private void initUsages(ItemKind kind, int itemCount) {
|
||||
List<List<String>> list = new ArrayList<>();
|
||||
if (atleastOne && itemCount == 0) {
|
||||
if (kind.hasReservedZeroIndex() && itemCount == 0) {
|
||||
itemCount = 1;
|
||||
}
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
@@ -80,17 +92,17 @@ public class ABCSimpleUsageDetector {
|
||||
public void detect() {
|
||||
usages.clear();
|
||||
|
||||
initUsages(ItemKind.INT, abc.constants.getIntCount(), true);
|
||||
initUsages(ItemKind.UINT, abc.constants.getUIntCount(), true);
|
||||
initUsages(ItemKind.DOUBLE, abc.constants.getDoubleCount(), true);
|
||||
initUsages(ItemKind.STRING, abc.constants.getStringCount(), true);
|
||||
initUsages(ItemKind.NAMESPACE, abc.constants.getNamespaceCount(), true);
|
||||
initUsages(ItemKind.NAMESPACESET, abc.constants.getNamespaceSetCount(), true);
|
||||
initUsages(ItemKind.MULTINAME, abc.constants.getMultinameCount(), true);
|
||||
initUsages(ItemKind.METADATAINFO, abc.metadata_info.size(), false);
|
||||
initUsages(ItemKind.METHODINFO, abc.method_info.size(), false);
|
||||
initUsages(ItemKind.METHODBODY, abc.bodies.size(), false);
|
||||
initUsages(ItemKind.CLASS, abc.class_info.size(), false);
|
||||
initUsages(ItemKind.INT, abc.constants.getIntCount());
|
||||
initUsages(ItemKind.UINT, abc.constants.getUIntCount());
|
||||
initUsages(ItemKind.DOUBLE, abc.constants.getDoubleCount());
|
||||
initUsages(ItemKind.STRING, abc.constants.getStringCount());
|
||||
initUsages(ItemKind.NAMESPACE, abc.constants.getNamespaceCount());
|
||||
initUsages(ItemKind.NAMESPACESET, abc.constants.getNamespaceSetCount());
|
||||
initUsages(ItemKind.MULTINAME, abc.constants.getMultinameCount());
|
||||
initUsages(ItemKind.METADATAINFO, abc.metadata_info.size());
|
||||
initUsages(ItemKind.METHODINFO, abc.method_info.size());
|
||||
initUsages(ItemKind.METHODBODY, abc.bodies.size());
|
||||
initUsages(ItemKind.CLASS, abc.class_info.size());
|
||||
|
||||
ABCWalker walker = new ABCWalker() {
|
||||
protected void handleUsageNamespace(int index, String usageDescription) {
|
||||
@@ -417,6 +429,16 @@ public class ABCSimpleUsageDetector {
|
||||
}
|
||||
};
|
||||
walker.walkABC(abc, false);
|
||||
|
||||
zeroUsages.clear();
|
||||
for (ItemKind kind : usages.keySet()) {
|
||||
zeroUsages.put(kind, new ArrayList<>());
|
||||
for (int i = kind.hasReservedZeroIndex() ? 1 : 0; i < usages.get(kind).size(); i++) {
|
||||
if (usages.get(kind).get(i).isEmpty()) {
|
||||
zeroUsages.get(kind).add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -445,4 +467,24 @@ public class ABCSimpleUsageDetector {
|
||||
public List<List<String>> getUsages(ItemKind kind) {
|
||||
return Collections.unmodifiableList(usages.get(kind));
|
||||
}
|
||||
|
||||
public Map<ItemKind, List<Integer>> getZeroUsages() {
|
||||
return Collections.unmodifiableMap(zeroUsages);
|
||||
}
|
||||
|
||||
public List<Integer> getZeroUsages(ItemKind kind) {
|
||||
return zeroUsages.get(kind);
|
||||
}
|
||||
|
||||
public int getZeroUsagesCount() {
|
||||
int cnt = 0;
|
||||
for (ItemKind kind : zeroUsages.keySet()) {
|
||||
cnt += zeroUsages.get(kind).size();
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
public int getZeroUsagesCount(ItemKind kind) {
|
||||
return zeroUsages.get(kind).size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,6 +185,16 @@ public class Amf3OutputStream extends OutputStream {
|
||||
os.write(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
os.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
os.write(b, off, len);
|
||||
}
|
||||
|
||||
private void writeArray(ArrayType val, Map<String, ObjectTypeSerializeHandler> serializers, List<String> stringTable, List<Traits> traitsTable, List<Object> objectTable) throws IOException, NoSerializerExistsException {
|
||||
int objectIndex = objectTable.indexOf(val);
|
||||
if (objectIndex == -1) {
|
||||
|
||||
@@ -1005,6 +1005,10 @@ public final class Configuration {
|
||||
@ConfigurationCategory("export")
|
||||
public static ConfigurationItem<Boolean> lastExportTransparentBackground = null;
|
||||
|
||||
@ConfigurationDefaultBoolean(true)
|
||||
@ConfigurationCategory("script")
|
||||
public static ConfigurationItem<Boolean> warningAbcOptimize = null;
|
||||
|
||||
private enum OSId {
|
||||
WINDOWS, OSX, UNIX
|
||||
}
|
||||
|
||||
@@ -56,6 +56,20 @@ public class FLVOutputStream extends OutputStream {
|
||||
pos++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
alignByte();
|
||||
os.write(b);
|
||||
pos += b.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
alignByte();
|
||||
os.write(b, off, len);
|
||||
pos += len;
|
||||
}
|
||||
|
||||
private void alignByte() throws IOException {
|
||||
if (bitPos > 0) {
|
||||
bitPos = 0;
|
||||
|
||||
@@ -117,6 +117,18 @@ public class GFxOutputStream extends OutputStream {
|
||||
pos++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
os.write(b);
|
||||
pos += b.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
os.write(b, off, len);
|
||||
pos += len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes SI32 (Signed 32bit integer) value to the stream
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user