mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-13 07:08:50 +00:00
ABC merging
This commit is contained in:
@@ -1237,7 +1237,7 @@ public class ABC {
|
||||
for (int i = 0; i < ins.definition.operands.length; i++) {
|
||||
if (ins.definition.operands[i] == AVM2Code.DAT_CLASS_INDEX) {
|
||||
if (ins.operands[i] >= index) {
|
||||
ins.operands[i]++;
|
||||
ins.setOperand(i, ins.operands[i] + 1, b.getCode(), b);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1272,8 +1272,7 @@ public class ABC {
|
||||
for (int i = 0; i < ins.definition.operands.length; i++) {
|
||||
if (ins.definition.operands[i] == AVM2Code.DAT_CLASS_INDEX) {
|
||||
if (ins.operands[i] > index) {
|
||||
ins.operands[i]--;
|
||||
b.setModified();
|
||||
ins.setOperand(i, ins.operands[i] - 1, b.getCode(), b);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1330,8 +1329,7 @@ public class ABC {
|
||||
for (int i = 0; i < ins.definition.operands.length; i++) {
|
||||
if (ins.definition.operands[i] == AVM2Code.DAT_METHOD_INDEX) {
|
||||
if (ins.operands[i] > index) {
|
||||
ins.operands[i]--;
|
||||
b.setModified();
|
||||
ins.setOperand(i, ins.operands[i] - 1, b.getCode(), b);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1453,24 +1451,137 @@ public class ABC {
|
||||
getMethodIndexing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges second ABC to this one.
|
||||
*
|
||||
* @param secondABC
|
||||
*/
|
||||
public void mergeABC(ABC secondABC) {
|
||||
Map<Integer, Integer> namespaceMap = new HashMap<>();
|
||||
Map<Integer, Integer> namespaceSetMap = new HashMap<>();
|
||||
Map<Integer, Integer> multinameMap = new HashMap<>();
|
||||
Map<Integer, Integer> methodInfoMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeStringMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeIntMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeUIntMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeDoubleMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeFloatMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeFloat4Map = new HashMap<>();
|
||||
Map<Integer, Integer> mergeDecimalMap = new HashMap<>();
|
||||
|
||||
constants.merge(secondABC.constants, namespaceMap, namespaceSetMap, multinameMap);
|
||||
Map<Integer, Integer> mergeNamespaceMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeNamespaceSetMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeMultinameMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeMethodInfoMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeMethodBodyMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeClassIndexMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeMetaDataMap = new HashMap<>();
|
||||
Map<Integer, Integer> mergeScriptInfoMap = new HashMap<>();
|
||||
|
||||
mergeABC(secondABC, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeNamespaceSetMap, mergeMultinameMap, mergeMethodInfoMap, mergeMethodBodyMap, mergeClassIndexMap, mergeMetaDataMap, mergeScriptInfoMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges second ABC to this one. Gets mapping of indices.
|
||||
*
|
||||
* @param secondABC
|
||||
* @param mergeStringMap
|
||||
* @param mergeIntMap
|
||||
* @param mergeUIntMap
|
||||
* @param mergeDoubleMap
|
||||
* @param mergeFloatMap
|
||||
* @param mergeFloat4Map
|
||||
* @param mergeDecimalMap
|
||||
* @param mergeNamespaceMap
|
||||
* @param mergeNamespaceSetMap
|
||||
* @param mergeMultinameMap
|
||||
* @param mergeMethodInfoMap
|
||||
* @param mergeMethodBodyMap
|
||||
* @param mergeClassIndexMap
|
||||
* @param mergeMetaDataMap
|
||||
* @param mergeScriptInfoMap
|
||||
*/
|
||||
public void mergeABC(ABC secondABC,
|
||||
Map<Integer, Integer> mergeStringMap,
|
||||
Map<Integer, Integer> mergeIntMap,
|
||||
Map<Integer, Integer> mergeUIntMap,
|
||||
Map<Integer, Integer> mergeDoubleMap,
|
||||
Map<Integer, Integer> mergeFloatMap,
|
||||
Map<Integer, Integer> mergeFloat4Map,
|
||||
Map<Integer, Integer> mergeDecimalMap,
|
||||
Map<Integer, Integer> mergeNamespaceMap,
|
||||
Map<Integer, Integer> mergeNamespaceSetMap,
|
||||
Map<Integer, Integer> mergeMultinameMap,
|
||||
Map<Integer, Integer> mergeMethodInfoMap,
|
||||
Map<Integer, Integer> mergeMethodBodyMap,
|
||||
Map<Integer, Integer> mergeClassIndexMap,
|
||||
Map<Integer, Integer> mergeMetaDataMap,
|
||||
Map<Integer, Integer> mergeScriptInfoMap
|
||||
) {
|
||||
|
||||
if (!version.equals(secondABC.version)) {
|
||||
throw new RuntimeException("ABC versions mismatch");
|
||||
}
|
||||
//Constants
|
||||
constants.merge(secondABC.constants, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeNamespaceSetMap, mergeMultinameMap);
|
||||
|
||||
//Metadata
|
||||
for (int m = 0; m < secondABC.metadata_info.size(); m++) {
|
||||
MetadataInfo secondMetadataInfo = secondABC.metadata_info.get(m);
|
||||
MetadataInfo newMetadataInfo = new MetadataInfo();
|
||||
newMetadataInfo.name_index = mergeStringMap.get(secondMetadataInfo.name_index);
|
||||
newMetadataInfo.keys = new int[secondMetadataInfo.keys.length];
|
||||
newMetadataInfo.values = new int[secondMetadataInfo.values.length];
|
||||
for (int i = 0; i < secondMetadataInfo.keys.length; i++) {
|
||||
newMetadataInfo.keys[i] = mergeStringMap.get(secondMetadataInfo.keys[i]);
|
||||
newMetadataInfo.values[i] = mergeStringMap.get(secondMetadataInfo.values[i]);
|
||||
}
|
||||
int newIndex = metadata_info.size();
|
||||
metadata_info.add(newMetadataInfo);
|
||||
mergeMetaDataMap.put(m, newIndex);
|
||||
}
|
||||
|
||||
//Method Info
|
||||
for (int i = 0; i < secondABC.method_info.size(); i++) {
|
||||
MethodInfo secondMethodInfo = secondABC.method_info.get(i);
|
||||
int newParamTypes[] = new int[secondMethodInfo.param_types.length];
|
||||
for (int t = 0; t < secondMethodInfo.param_types.length; t++) {
|
||||
newParamTypes[t] = mergeMultinameMap.get(secondMethodInfo.param_types[t]);
|
||||
}
|
||||
int newParamNames[] = new int[secondMethodInfo.paramNames.length];
|
||||
int newRetType = multinameMap.get(secondMethodInfo.ret_type);
|
||||
int newNameIndex = constants.getStringId(secondABC.constants.getString(secondMethodInfo.name_index), true);
|
||||
for (int n = 0; n < secondMethodInfo.paramNames.length; n++) {
|
||||
newParamNames[n] = mergeStringMap.get(secondMethodInfo.paramNames[n]);
|
||||
}
|
||||
int newRetType = mergeMultinameMap.get(secondMethodInfo.ret_type);
|
||||
int newNameIndex = mergeStringMap.get(secondMethodInfo.name_index);
|
||||
ValueKind newOptional[] = new ValueKind[secondMethodInfo.optional.length];
|
||||
for (int k = 0; k < secondMethodInfo.optional.length; k++) {
|
||||
int vkind = secondMethodInfo.optional[k].value_kind;
|
||||
int newValueIndex;
|
||||
Map<Integer, Integer> valueMergeMap = null;
|
||||
switch (vkind) {
|
||||
case ValueKind.CONSTANT_Utf8:
|
||||
valueMergeMap = mergeStringMap;
|
||||
break;
|
||||
case ValueKind.CONSTANT_Int:
|
||||
valueMergeMap = mergeIntMap;
|
||||
break;
|
||||
case ValueKind.CONSTANT_UInt:
|
||||
valueMergeMap = mergeUIntMap;
|
||||
break;
|
||||
case ValueKind.CONSTANT_Double:
|
||||
valueMergeMap = mergeDoubleMap;
|
||||
break;
|
||||
case ValueKind.CONSTANT_DecimalOrFloat:
|
||||
//assuming the second ABC has same decimal/float support
|
||||
if (hasDecimalSupport()) {
|
||||
valueMergeMap = mergeDecimalMap;
|
||||
} else if (hasFloatSupport()) {
|
||||
valueMergeMap = mergeFloatMap;
|
||||
} else {
|
||||
//should not happen
|
||||
}
|
||||
break;
|
||||
case ValueKind.CONSTANT_Float4:
|
||||
if (hasFloatSupport()) {
|
||||
valueMergeMap = mergeFloat4Map;
|
||||
}
|
||||
break;
|
||||
case ValueKind.CONSTANT_ExplicitNamespace:
|
||||
case ValueKind.CONSTANT_Namespace:
|
||||
case ValueKind.CONSTANT_PackageInternalNs:
|
||||
@@ -1478,25 +1589,264 @@ public class ABC {
|
||||
case ValueKind.CONSTANT_ProtectedNamespace:
|
||||
case ValueKind.CONSTANT_PrivateNs:
|
||||
case ValueKind.CONSTANT_StaticProtectedNs:
|
||||
newValueIndex = namespaceMap.get(secondMethodInfo.optional[k].value_index);
|
||||
valueMergeMap = mergeNamespaceMap;
|
||||
break;
|
||||
default:
|
||||
newValueIndex = secondMethodInfo.optional[k].value_index;
|
||||
}
|
||||
|
||||
int newValueIndex = valueMergeMap != null ? valueMergeMap.get(secondMethodInfo.optional[k].value_index) : secondMethodInfo.optional[k].value_index;
|
||||
newOptional[k] = new ValueKind(newValueIndex, vkind);
|
||||
}
|
||||
|
||||
MethodInfo newMethodInfo = new MethodInfo(newParamTypes, newRetType, newNameIndex, secondMethodInfo.flags, newOptional, newParamNames);
|
||||
int newIndex = addMethodInfo(newMethodInfo);
|
||||
methodInfoMap.put(i, newIndex);
|
||||
mergeMethodInfoMap.put(i, newIndex);
|
||||
}
|
||||
for (MethodBody secondBody : secondABC.bodies) {
|
||||
//TODO!!!
|
||||
//MethodBody newBody = new MethodBody(this, mergeTraits(secondBody.traits), codeBytes, exceptions)
|
||||
|
||||
int classFirstIndex = class_info.size();
|
||||
//Class/Instance
|
||||
for (int c = 0; c < secondABC.class_info.size(); c++) {
|
||||
ClassInfo secondClassInfo = secondABC.class_info.get(c);
|
||||
ClassInfo newClassInfo = new ClassInfo();
|
||||
int newIndex = class_info.size();
|
||||
class_info.add(newClassInfo);
|
||||
mergeClassIndexMap.put(c, newIndex);
|
||||
newClassInfo.cinit_index = mergeMethodInfoMap.get(secondClassInfo.cinit_index);
|
||||
|
||||
newClassInfo.lastDispId = secondClassInfo.lastDispId;
|
||||
InstanceInfo secondInstanceInfo = secondABC.instance_info.get(c);
|
||||
InstanceInfo newInstanceInfo = new InstanceInfo();
|
||||
newInstanceInfo.iinit_index = mergeMethodInfoMap.get(secondInstanceInfo.iinit_index);
|
||||
newInstanceInfo.super_index = mergeMultinameMap.get(secondInstanceInfo.super_index);
|
||||
newInstanceInfo.interfaces = new int[secondInstanceInfo.interfaces.length];
|
||||
for (int i = 0; i < secondInstanceInfo.interfaces.length; i++) {
|
||||
newInstanceInfo.interfaces[i] = mergeMultinameMap.get(secondInstanceInfo.interfaces[i]);
|
||||
}
|
||||
newInstanceInfo.protectedNS = mergeNamespaceMap.get(secondInstanceInfo.protectedNS);
|
||||
newInstanceInfo.name_index = mergeMultinameMap.get(secondInstanceInfo.name_index);
|
||||
newInstanceInfo.flags = secondInstanceInfo.flags;
|
||||
instance_info.add(newInstanceInfo);
|
||||
|
||||
//do traits in second step as some classes may depend on other classes
|
||||
}
|
||||
|
||||
//Class/Instance traits
|
||||
for (int c = 0; c < secondABC.class_info.size(); c++) {
|
||||
ClassInfo secondClassInfo = secondABC.class_info.get(c);
|
||||
InstanceInfo secondInstanceInfo = secondABC.instance_info.get(c);
|
||||
ClassInfo newClassInfo = class_info.get(classFirstIndex + c);
|
||||
InstanceInfo newInstanceInfo = instance_info.get(classFirstIndex + c);
|
||||
newClassInfo.static_traits = mergeTraits(secondClassInfo.static_traits, mergeMultinameMap, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeMetaDataMap, mergeMethodInfoMap, mergeClassIndexMap);
|
||||
newInstanceInfo.instance_traits = mergeTraits(secondInstanceInfo.instance_traits, mergeMultinameMap, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeMetaDataMap, mergeMethodInfoMap, mergeClassIndexMap);
|
||||
}
|
||||
|
||||
//Scripts
|
||||
for (int s = 0; s < secondABC.script_info.size(); s++) {
|
||||
ScriptInfo secondScriptInfo = secondABC.script_info.get(s);
|
||||
ScriptInfo newScriptInfo = new ScriptInfo();
|
||||
newScriptInfo.init_index = mergeMethodInfoMap.get(secondScriptInfo.init_index);
|
||||
newScriptInfo.traits = mergeTraits(secondScriptInfo.traits, mergeMultinameMap, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeMetaDataMap, mergeMethodInfoMap, mergeClassIndexMap);
|
||||
int newIndex = script_info.size();
|
||||
script_info.add(newScriptInfo);
|
||||
mergeScriptInfoMap.put(s, newIndex);
|
||||
}
|
||||
|
||||
//Method bodies
|
||||
for (int b = 0; b < secondABC.bodies.size(); b++) {
|
||||
MethodBody secondBody = secondABC.bodies.get(b);
|
||||
MethodBody newBody = secondBody.clone(true);
|
||||
newBody.method_info = mergeMethodInfoMap.get(secondBody.method_info);
|
||||
for (int e = 0; e < secondBody.exceptions.length; e++) {
|
||||
newBody.exceptions[e].name_index = mergeMultinameMap.get(secondBody.exceptions[e].name_index);
|
||||
newBody.exceptions[e].type_index = mergeMultinameMap.get(secondBody.exceptions[e].type_index);
|
||||
}
|
||||
AVM2Code newCode = newBody.getCode();
|
||||
for (AVM2Instruction newIns : newCode.code) {
|
||||
int newOperands[] = newIns.operands == null ? null : newIns.operands.clone();
|
||||
boolean modified = false;
|
||||
if (newIns.operands != null) {
|
||||
for (int i = 0; i < newIns.definition.operands.length; i++) {
|
||||
Map<Integer, Integer> mergeMap = null;
|
||||
switch (newIns.definition.operands[i]) {
|
||||
case AVM2Code.DAT_CLASS_INDEX:
|
||||
mergeMap = mergeClassIndexMap;
|
||||
break;
|
||||
case AVM2Code.DAT_STRING_INDEX:
|
||||
mergeMap = mergeStringMap;
|
||||
break;
|
||||
case AVM2Code.DAT_INT_INDEX:
|
||||
mergeMap = mergeIntMap;
|
||||
break;
|
||||
case AVM2Code.DAT_UINT_INDEX:
|
||||
mergeMap = mergeUIntMap;
|
||||
break;
|
||||
case AVM2Code.DAT_DOUBLE_INDEX:
|
||||
mergeMap = mergeDoubleMap;
|
||||
break;
|
||||
case AVM2Code.DAT_DECIMAL_INDEX:
|
||||
mergeMap = mergeDecimalMap;
|
||||
break;
|
||||
case AVM2Code.DAT_FLOAT_INDEX:
|
||||
mergeMap = mergeFloatMap;
|
||||
break;
|
||||
case AVM2Code.DAT_FLOAT4_INDEX:
|
||||
mergeMap = mergeFloat4Map;
|
||||
break;
|
||||
case AVM2Code.DAT_NAMESPACE_INDEX:
|
||||
mergeMap = mergeNamespaceMap;
|
||||
break;
|
||||
case AVM2Code.DAT_METHOD_INDEX:
|
||||
mergeMap = mergeMethodInfoMap;
|
||||
break;
|
||||
case AVM2Code.DAT_MULTINAME_INDEX:
|
||||
mergeMap = mergeMultinameMap;
|
||||
break;
|
||||
}
|
||||
if (mergeMap != null) {
|
||||
newOperands[i] = mergeMap.get(newIns.operands[i]);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
newIns.setOperands(newOperands, newCode, newBody);
|
||||
}
|
||||
newBody.traits = mergeTraits(secondBody.traits, mergeMultinameMap, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeMetaDataMap, mergeMethodInfoMap, mergeClassIndexMap);
|
||||
}
|
||||
newBody.setModified();
|
||||
int newIndex = bodies.size();
|
||||
bodies.add(newBody);
|
||||
mergeMethodBodyMap.put(b, newIndex);
|
||||
}
|
||||
|
||||
//clear caches
|
||||
abcMethodIndexing = null;
|
||||
getSwf().clearScriptCache();
|
||||
((Tag) parentTag).setModified(true);
|
||||
}
|
||||
|
||||
private Traits mergeTraits(Traits secondTraits) {
|
||||
return null; //TODO
|
||||
private Traits mergeTraits(Traits secondTraits, Map<Integer, Integer> mergeMultinameMap,
|
||||
Map<Integer, Integer> mergeStringMap,
|
||||
Map<Integer, Integer> mergeIntMap,
|
||||
Map<Integer, Integer> mergeUIntMap,
|
||||
Map<Integer, Integer> mergeDoubleMap,
|
||||
Map<Integer, Integer> mergeFloatMap,
|
||||
Map<Integer, Integer> mergeFloat4Map,
|
||||
Map<Integer, Integer> mergeDecimalMap,
|
||||
Map<Integer, Integer> mergeNamespaceMap,
|
||||
Map<Integer, Integer> mergeMetaDataMap,
|
||||
Map<Integer, Integer> mergeMethodInfoMap,
|
||||
Map<Integer, Integer> mergeClassIndexMap) {
|
||||
Traits newTraits = new Traits();
|
||||
for (Trait t : secondTraits.traits) {
|
||||
Trait newTrait = null;
|
||||
if (t instanceof TraitMethodGetterSetter) {
|
||||
newTrait = mergeTrait((TraitMethodGetterSetter) t, mergeMultinameMap, mergeMethodInfoMap, mergeMetaDataMap);
|
||||
} else if (t instanceof TraitSlotConst) {
|
||||
newTrait = mergeTrait((TraitSlotConst) t, mergeMultinameMap, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeMetaDataMap);
|
||||
} else if (t instanceof TraitFunction) {
|
||||
newTrait = mergeTrait((TraitFunction) t, mergeMultinameMap, mergeMethodInfoMap, mergeMetaDataMap);
|
||||
} else if (t instanceof TraitClass) {
|
||||
newTrait = mergeTrait((TraitClass) t, mergeClassIndexMap, mergeMultinameMap, mergeMetaDataMap);
|
||||
} else {
|
||||
//should not happen
|
||||
}
|
||||
|
||||
newTraits.addTrait(newTrait);
|
||||
|
||||
}
|
||||
return newTraits;
|
||||
}
|
||||
|
||||
private TraitMethodGetterSetter mergeTrait(TraitMethodGetterSetter secondTrait, Map<Integer, Integer> mergeMultinameMap, Map<Integer, Integer> mergeMethodInfoMap, Map<Integer, Integer> mergeMetaDataMap) {
|
||||
TraitMethodGetterSetter newTrait = secondTrait.clone();
|
||||
newTrait.method_info = mergeMethodInfoMap.get(secondTrait.method_info);
|
||||
newTrait.name_index = mergeMultinameMap.get(secondTrait.name_index);
|
||||
for (int m = 0; m < secondTrait.metadata.length; m++) {
|
||||
newTrait.metadata[m] = mergeMetaDataMap.get(secondTrait.metadata[m]);
|
||||
}
|
||||
return newTrait;
|
||||
}
|
||||
|
||||
private TraitSlotConst mergeTrait(TraitSlotConst secondTrait, Map<Integer, Integer> mergeMultinameMap,
|
||||
Map<Integer, Integer> mergeStringMap,
|
||||
Map<Integer, Integer> mergeIntMap,
|
||||
Map<Integer, Integer> mergeUIntMap,
|
||||
Map<Integer, Integer> mergeDoubleMap,
|
||||
Map<Integer, Integer> mergeFloatMap,
|
||||
Map<Integer, Integer> mergeFloat4Map,
|
||||
Map<Integer, Integer> mergeDecimalMap,
|
||||
Map<Integer, Integer> mergeNamespaceMap,
|
||||
Map<Integer, Integer> mergeMetaDataMap
|
||||
) {
|
||||
TraitSlotConst newTrait = secondTrait.clone();
|
||||
newTrait.name_index = mergeMultinameMap.get(secondTrait.name_index);
|
||||
for (int m = 0; m < secondTrait.metadata.length; m++) {
|
||||
newTrait.metadata[m] = mergeMetaDataMap.get(secondTrait.metadata[m]);
|
||||
}
|
||||
newTrait.type_index = mergeMultinameMap.get(secondTrait.type_index);
|
||||
Map<Integer, Integer> valueMergeMap = null;
|
||||
|
||||
switch (newTrait.value_kind) {
|
||||
case ValueKind.CONSTANT_Utf8:
|
||||
valueMergeMap = mergeStringMap;
|
||||
break;
|
||||
case ValueKind.CONSTANT_Int:
|
||||
valueMergeMap = mergeIntMap;
|
||||
break;
|
||||
case ValueKind.CONSTANT_UInt:
|
||||
valueMergeMap = mergeUIntMap;
|
||||
break;
|
||||
case ValueKind.CONSTANT_Double:
|
||||
valueMergeMap = mergeDoubleMap;
|
||||
break;
|
||||
case ValueKind.CONSTANT_DecimalOrFloat:
|
||||
//assuming the second ABC has same decimal/float support
|
||||
if (hasDecimalSupport()) {
|
||||
valueMergeMap = mergeDecimalMap;
|
||||
} else if (hasFloatSupport()) {
|
||||
valueMergeMap = mergeFloatMap;
|
||||
} else {
|
||||
//should not happen
|
||||
}
|
||||
break;
|
||||
case ValueKind.CONSTANT_Float4:
|
||||
if (hasFloatSupport()) {
|
||||
valueMergeMap = mergeFloat4Map;
|
||||
}
|
||||
break;
|
||||
case ValueKind.CONSTANT_ExplicitNamespace:
|
||||
case ValueKind.CONSTANT_Namespace:
|
||||
case ValueKind.CONSTANT_PackageInternalNs:
|
||||
case ValueKind.CONSTANT_PackageNamespace:
|
||||
case ValueKind.CONSTANT_PrivateNs:
|
||||
case ValueKind.CONSTANT_ProtectedNamespace:
|
||||
case ValueKind.CONSTANT_StaticProtectedNs:
|
||||
valueMergeMap = mergeNamespaceMap;
|
||||
break;
|
||||
}
|
||||
if (valueMergeMap != null) {
|
||||
newTrait.value_index = valueMergeMap.get(secondTrait.value_index);
|
||||
}
|
||||
return newTrait; //TODO
|
||||
}
|
||||
|
||||
private TraitFunction mergeTrait(TraitFunction secondTrait, Map<Integer, Integer> mergeMultinameMap, Map<Integer, Integer> mergeMethodInfoMap, Map<Integer, Integer> mergeMetaDataMap) {
|
||||
TraitFunction newTrait = secondTrait.clone();
|
||||
newTrait.method_info = mergeMethodInfoMap.get(secondTrait.method_info);
|
||||
newTrait.name_index = mergeMultinameMap.get(secondTrait.name_index);
|
||||
for (int m = 0; m < secondTrait.metadata.length; m++) {
|
||||
newTrait.metadata[m] = mergeMetaDataMap.get(secondTrait.metadata[m]);
|
||||
}
|
||||
return newTrait;
|
||||
}
|
||||
|
||||
private TraitClass mergeTrait(TraitClass secondTrait, Map<Integer, Integer> mergeClassMap, Map<Integer, Integer> mergeMultinameMap, Map<Integer, Integer> mergeMetaDataMap) {
|
||||
TraitClass newTrait = secondTrait.clone();
|
||||
newTrait.class_info = mergeClassMap.get(secondTrait.class_info);
|
||||
newTrait.name_index = mergeMultinameMap.get(secondTrait.name_index);
|
||||
for (int m = 0; m < secondTrait.metadata.length; m++) {
|
||||
newTrait.metadata[m] = mergeMetaDataMap.get(secondTrait.metadata[m]);
|
||||
}
|
||||
return newTrait;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,4 +27,27 @@ public class ABCVersion implements Comparable<ABCVersion> {
|
||||
return "" + major + "." + minor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 53 * hash + this.major;
|
||||
hash = 53 * hash + this.minor;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final ABCVersion other = (ABCVersion) obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1100,6 +1100,11 @@ public class AVM2Code implements Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
public void setInstructionOperand(int ip, int operandIndex, int value, MethodBody body) {
|
||||
int oldVal = code.get(ip).operands[ip];
|
||||
code.get(ip).operands[ip] = value;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return getBytes(null);
|
||||
}
|
||||
@@ -2145,6 +2150,38 @@ public class AVM2Code implements Cloneable {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void updateInstructionByteCountByAddr(long instructionAddress, int byteDelta, MethodBody body) {
|
||||
if (byteDelta != 0) {
|
||||
updateOffsets(new OffsetUpdater() {
|
||||
|
||||
@Override
|
||||
public long updateInstructionOffset(long address) {
|
||||
if (address > instructionAddress) {
|
||||
return address + byteDelta;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateOperandOffset(long insAddr, long targetAddress, int offset) {
|
||||
if (targetAddress > instructionAddress && insAddr <= instructionAddress) {
|
||||
return offset + byteDelta;
|
||||
}
|
||||
if (targetAddress <= instructionAddress && insAddr > instructionAddress) {
|
||||
return offset - byteDelta;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
}, body);
|
||||
body.setModified();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateInstructionByteCount(int pos, int byteDelta, MethodBody body) {
|
||||
AVM2Instruction instruction = code.get(pos);
|
||||
updateInstructionByteCountByAddr(instruction.getAddress(), byteDelta, body);
|
||||
}
|
||||
|
||||
public void updateOffsets(OffsetUpdater updater, MethodBody body) {
|
||||
for (int i = 0; i < code.size(); i++) {
|
||||
AVM2Instruction ins = code.get(i);
|
||||
@@ -2172,6 +2209,7 @@ public class AVM2Code implements Cloneable {
|
||||
}
|
||||
}
|
||||
ins.setAddress(updater.updateInstructionOffset(ins.getAddress()));
|
||||
//Note: changing operands here does not change instruction byte length as offsets are always S24 (not variable length)
|
||||
}
|
||||
|
||||
for (ABCException ex : body.exceptions) {
|
||||
|
||||
@@ -772,50 +772,68 @@ public class AVM2ConstantPool implements Cloneable {
|
||||
* Merges second constantpool into this one
|
||||
*
|
||||
* @param secondPool
|
||||
* @param namespaceMap Output map of merged namespaces. Index in second pool
|
||||
* to index in this pool.
|
||||
* @param namespaceSetMap Output map of merged namespace sets. Index in
|
||||
* second pool to index in this pool.
|
||||
* @param multinameMap Output map of merged multinames. Index in second pool
|
||||
* to index in this pool.
|
||||
* @param stringMap
|
||||
* @param intMap
|
||||
* @param uintMap
|
||||
* @param doubleMap
|
||||
* @param floatMap
|
||||
* @param float4Map
|
||||
* @param decimalMap
|
||||
* @param namespaceMap
|
||||
* @param namespaceSetMap
|
||||
* @param multinameMap
|
||||
*/
|
||||
public void merge(AVM2ConstantPool secondPool, Map<Integer, Integer> namespaceMap, Map<Integer, Integer> namespaceSetMap, Map<Integer, Integer> multinameMap) {
|
||||
for (String val : secondPool.constant_string) {
|
||||
getStringId(val, true);
|
||||
public void merge(AVM2ConstantPool secondPool, Map<Integer, Integer> stringMap, Map<Integer, Integer> intMap, Map<Integer, Integer> uintMap, Map<Integer, Integer> doubleMap, Map<Integer, Integer> floatMap, Map<Integer, Integer> float4Map, Map<Integer, Integer> decimalMap, Map<Integer, Integer> namespaceMap, Map<Integer, Integer> namespaceSetMap, Map<Integer, Integer> multinameMap) {
|
||||
stringMap.put(0, 0);
|
||||
for (int i = 1; i < secondPool.constant_string.size(); i++) {
|
||||
String val = secondPool.constant_string.get(i);
|
||||
stringMap.put(i, getStringId(val, true));
|
||||
}
|
||||
for (Long val : secondPool.constant_int) {
|
||||
getIntId(val, true);
|
||||
intMap.put(0, 0);
|
||||
for (int i = 1; i < secondPool.constant_int.size(); i++) {
|
||||
Long val = secondPool.constant_int.get(i);
|
||||
intMap.put(i, getIntId(val, true));
|
||||
}
|
||||
for (Long val : secondPool.constant_uint) {
|
||||
getUIntId(val, true);
|
||||
uintMap.put(0, 0);
|
||||
for (int i = 1; i < secondPool.constant_uint.size(); i++) {
|
||||
Long val = secondPool.constant_uint.get(i);
|
||||
uintMap.put(i, getUIntId(val, true));
|
||||
}
|
||||
for (Double val : secondPool.constant_double) {
|
||||
getDoubleId(val, true);
|
||||
doubleMap.put(0, 0);
|
||||
for (int i = 1; i < secondPool.constant_double.size(); i++) {
|
||||
Double val = secondPool.constant_double.get(i);
|
||||
doubleMap.put(i, getDoubleId(val, true));
|
||||
}
|
||||
for (Float val : secondPool.constant_float) {
|
||||
getFloatId(val, true);
|
||||
floatMap.put(0, 0);
|
||||
for (int i = 1; i < secondPool.constant_float.size(); i++) {
|
||||
Float val = secondPool.constant_float.get(i);
|
||||
floatMap.put(i, getFloatId(val, true));
|
||||
}
|
||||
for (Float4 val : secondPool.constant_float4) {
|
||||
getFloat4Id(val, true);
|
||||
float4Map.put(0, 0);
|
||||
for (int i = 1; i < secondPool.constant_float4.size(); i++) {
|
||||
Float4 val = secondPool.constant_float4.get(i);
|
||||
float4Map.put(i, getFloat4Id(val, true));
|
||||
}
|
||||
for (Decimal val : secondPool.constant_decimal) {
|
||||
getDecimalId(val, true);
|
||||
decimalMap.put(0, 0);
|
||||
for (int i = 1; i < secondPool.constant_decimal.size(); i++) {
|
||||
Decimal val = secondPool.constant_decimal.get(i);
|
||||
decimalMap.put(i, getDecimalId(val, true));
|
||||
}
|
||||
namespaceMap.put(0, 0);
|
||||
for (int i = 1; i < secondPool.constant_namespace.size(); i++) {
|
||||
Namespace secondNamespace = secondPool.getNamespace(i);
|
||||
String secondNsNameStr = secondNamespace.name_index == 0 ? null : secondPool.getString(secondNamespace.name_index);
|
||||
Namespace secondNamespace = secondPool.constant_namespace.get(i);
|
||||
int mappedId;
|
||||
int newNameIndex = stringMap.get(secondNamespace.name_index);
|
||||
if (secondNamespace.kind == Namespace.KIND_PRIVATE) {//always add, this does not exists in this ABC. Conflicting private namespaces can have same names.
|
||||
mappedId = addNamespace(secondNamespace.kind, getStringId(secondNsNameStr, true));
|
||||
mappedId = addNamespace(secondNamespace.kind, newNameIndex);
|
||||
} else {
|
||||
mappedId = getNamespaceId(secondNamespace.kind, secondNsNameStr, 0, true);
|
||||
mappedId = getNamespaceId(secondNamespace.kind, newNameIndex, 0, true);
|
||||
}
|
||||
namespaceMap.put(i, mappedId);
|
||||
}
|
||||
namespaceSetMap.put(0, 0);
|
||||
for (int i = 1; i < secondPool.constant_namespace_set.size(); i++) {
|
||||
NamespaceSet secondNamespaceSet = secondPool.getNamespaceSet(i);
|
||||
NamespaceSet secondNamespaceSet = secondPool.constant_namespace_set.get(i);
|
||||
int mappedsNss[] = new int[secondNamespaceSet.namespaces.length];
|
||||
for (int n = 0; n < secondNamespaceSet.namespaces.length; n++) {
|
||||
mappedsNss[n] = namespaceMap.get(secondNamespaceSet.namespaces[n]);
|
||||
@@ -825,42 +843,42 @@ public class AVM2ConstantPool implements Cloneable {
|
||||
}
|
||||
multinameMap.put(0, 0);
|
||||
for (int i = 1; i < secondPool.constant_multiname.size(); i++) {
|
||||
Multiname secondMultiname = secondPool.getMultiname(i);
|
||||
Multiname importedMultiname = null;
|
||||
int newNameIndex = secondMultiname.name_index <= 0 ? secondMultiname.name_index : getStringId(secondPool.getString(secondMultiname.name_index), true);
|
||||
Multiname secondMultiname = secondPool.constant_multiname.get(i);
|
||||
Multiname newMultiname = null;
|
||||
int newNameIndex = secondMultiname.name_index <= 0 ? secondMultiname.name_index : stringMap.get(secondMultiname.name_index);
|
||||
int newNsIndex = secondMultiname.namespace_index <= 0 ? secondMultiname.namespace_index : namespaceMap.get(secondMultiname.namespace_index);
|
||||
int newNssIndex = secondMultiname.namespace_set_index <= 0 ? secondMultiname.namespace_set_index : namespaceSetMap.get(secondMultiname.namespace_set_index);
|
||||
|
||||
switch (secondMultiname.kind) {
|
||||
case Multiname.MULTINAME:
|
||||
importedMultiname = Multiname.createMultiname(false, newNameIndex, newNssIndex);
|
||||
newMultiname = Multiname.createMultiname(false, newNameIndex, newNssIndex);
|
||||
break;
|
||||
case Multiname.MULTINAMEA:
|
||||
importedMultiname = Multiname.createMultiname(true, newNameIndex, newNssIndex);
|
||||
newMultiname = Multiname.createMultiname(true, newNameIndex, newNssIndex);
|
||||
break;
|
||||
case Multiname.MULTINAMEL:
|
||||
importedMultiname = Multiname.createMultinameL(false, newNssIndex);
|
||||
newMultiname = Multiname.createMultinameL(false, newNssIndex);
|
||||
break;
|
||||
case Multiname.MULTINAMELA:
|
||||
importedMultiname = Multiname.createMultinameL(true, newNssIndex);
|
||||
newMultiname = Multiname.createMultinameL(true, newNssIndex);
|
||||
break;
|
||||
case Multiname.QNAME:
|
||||
importedMultiname = Multiname.createQName(false, newNameIndex, newNsIndex);
|
||||
newMultiname = Multiname.createQName(false, newNameIndex, newNsIndex);
|
||||
break;
|
||||
case Multiname.QNAMEA:
|
||||
importedMultiname = Multiname.createQName(true, newNameIndex, newNsIndex);
|
||||
newMultiname = Multiname.createQName(true, newNameIndex, newNsIndex);
|
||||
break;
|
||||
case Multiname.RTQNAME:
|
||||
importedMultiname = Multiname.createRTQName(false, newNameIndex);
|
||||
newMultiname = Multiname.createRTQName(false, newNameIndex);
|
||||
break;
|
||||
case Multiname.RTQNAMEA:
|
||||
importedMultiname = Multiname.createRTQName(true, newNameIndex);
|
||||
newMultiname = Multiname.createRTQName(true, newNameIndex);
|
||||
break;
|
||||
case Multiname.RTQNAMEL:
|
||||
importedMultiname = Multiname.createRTQNameL(false);
|
||||
newMultiname = Multiname.createRTQNameL(false);
|
||||
break;
|
||||
case Multiname.RTQNAMELA:
|
||||
importedMultiname = Multiname.createRTQNameL(true);
|
||||
newMultiname = Multiname.createRTQNameL(true);
|
||||
break;
|
||||
case Multiname.TYPENAME:
|
||||
int newQnameIndex = multinameMap.get(secondMultiname.qname_index);
|
||||
@@ -868,11 +886,11 @@ public class AVM2ConstantPool implements Cloneable {
|
||||
for (int p = 0; p < secondMultiname.params.length; p++) {
|
||||
newParams[p] = multinameMap.get(secondMultiname.params[p]);
|
||||
}
|
||||
importedMultiname = Multiname.createTypeName(newQnameIndex, newParams);
|
||||
newMultiname = Multiname.createTypeName(newQnameIndex, newParams);
|
||||
break;
|
||||
}
|
||||
|
||||
int mappedId = getMultinameId(importedMultiname, true);
|
||||
int mappedId = getMultinameId(newMultiname, true);
|
||||
multinameMap.put(i, mappedId);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns;
|
||||
import com.jpexs.decompiler.flash.abc.types.Float4;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
@@ -488,4 +489,42 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set operand value the right way - update offsets neccessarily. Because
|
||||
* some operand types are variable length (like U30)
|
||||
*
|
||||
* @param operandIndex
|
||||
* @param newValue
|
||||
* @param code
|
||||
* @param body
|
||||
*/
|
||||
public void setOperand(int operandIndex, int newValue, AVM2Code code, MethodBody body) {
|
||||
int oldByteCount = getBytesLength();
|
||||
operands[operandIndex] = newValue;
|
||||
int newByteCount = getBytesLength();
|
||||
int byteDelta = newByteCount - oldByteCount;
|
||||
if (byteDelta != 0) {
|
||||
code.updateInstructionByteCountByAddr(address, byteDelta, body);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set operand values the right way - update offsets neccessarily. Because
|
||||
* some operand types are variable length (like U30)
|
||||
*
|
||||
* @param operands
|
||||
* @param code
|
||||
* @param body
|
||||
*/
|
||||
public void setOperands(int operands[], AVM2Code code, MethodBody body) {
|
||||
int oldByteCount = getBytesLength();
|
||||
this.operands = operands;
|
||||
int newByteCount = getBytesLength();
|
||||
int byteDelta = newByteCount - oldByteCount;
|
||||
if (byteDelta != 0) {
|
||||
code.updateInstructionByteCountByAddr(address, byteDelta, body);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -424,6 +424,10 @@ public final class MethodBody implements Cloneable {
|
||||
|
||||
@Override
|
||||
public MethodBody clone() {
|
||||
return clone(false);
|
||||
}
|
||||
|
||||
public MethodBody clone(boolean deepTraits) {
|
||||
try {
|
||||
MethodBody ret = (MethodBody) super.clone();
|
||||
if (code != null) {
|
||||
@@ -437,10 +441,9 @@ public final class MethodBody implements Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
// maybe deep clone traits
|
||||
/*if (traits != null) {
|
||||
ret.traits = traits.clone();
|
||||
}*/
|
||||
if (deepTraits && traits != null) {
|
||||
ret.traits = traits.clone();
|
||||
}
|
||||
ret.convertedItems = null;
|
||||
ret.convertException = null;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import com.jpexs.helpers.Helper;
|
||||
*/
|
||||
public class ValueKind {
|
||||
|
||||
public static final int CONSTANT_Decimal = 0x02; //decimal
|
||||
public static final int CONSTANT_DecimalOrFloat = 0x02; //decimal or float depending on ABC version
|
||||
|
||||
public static final int CONSTANT_Int = 0x03;// integer
|
||||
|
||||
@@ -57,6 +57,8 @@ public class ValueKind {
|
||||
|
||||
public static final int CONSTANT_PrivateNs = 0x05;// namespace
|
||||
|
||||
public static final int CONSTANT_Float4 = 0x1E;// float4
|
||||
|
||||
private static final int[] optionalKinds = new int[]{0x03, 0x04, 0x06, 0x02, 0x01, 0x0B, 0x0A, 0x0C, 0x00, 0x08, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x05};
|
||||
|
||||
private static final String[] optionalKindNames = new String[]{"Int", "UInt", "Double", "Decimal", "Utf8", "True", "False", "Null", "Undefined", "Namespace", "PackageNamespace", "PackageInternalNs", "ProtectedNamespace", "ExplicitNamespace", "StaticProtectedNs", "PrivateNamespace"};
|
||||
@@ -137,7 +139,7 @@ public class ValueKind {
|
||||
case CONSTANT_Double:
|
||||
ret = "" + constants.getDouble(value_index);
|
||||
break;
|
||||
case CONSTANT_Decimal:
|
||||
case CONSTANT_DecimalOrFloat:
|
||||
ret = "" + constants.getDecimal(value_index);
|
||||
break;
|
||||
case CONSTANT_Utf8:
|
||||
@@ -179,7 +181,7 @@ public class ValueKind {
|
||||
case CONSTANT_Double:
|
||||
ret = "Double(" + constants.getDouble(value_index) + ")";
|
||||
break;
|
||||
case CONSTANT_Decimal:
|
||||
case CONSTANT_DecimalOrFloat:
|
||||
ret = "Decimal(" + constants.getDecimal(value_index) + ")";
|
||||
break;
|
||||
case CONSTANT_Utf8:
|
||||
|
||||
Reference in New Issue
Block a user