/* * Copyright (C) 2010-2016 JPEXS, All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. */ package com.jpexs.decompiler.flash.abc.avm2.deobfuscation; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.types.Multiname; import com.jpexs.decompiler.flash.abc.types.NamespaceSet; import com.jpexs.decompiler.flash.abc.usages.MultinameUsage; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.flash.tags.Tag; import java.util.HashSet; import java.util.Objects; import java.util.Set; public class AbcMultiNameCollisionFixer { public int fixCollisions(SWF swf) { int ret = 0; for (ABCContainerTag tag : swf.getAbcList()) { ret += this.fixCollisions(tag.getABC()); } return ret; } public int fixCollisions(ABC abc) { Set<MultinameUsage> collidingUsages = abc.getCollidingMultinameUsages(); Set<Integer> collidingMultinameIndices = new HashSet<>(); for (MultinameUsage usage : collidingUsages) { collidingMultinameIndices.add(usage.getMultinameIndex()); } Set<String> newNames = new HashSet<>(); int ret = 0; for (int multiNameIndex : collidingMultinameIndices) { Multiname multiName = abc.constants.getMultiname(multiNameIndex); int namespace = multiName.namespace_index; String oldName = abc.constants.getString(multiName.name_index); String selectedBaseName = oldName + "_" + multiName.namespace_index; String selectedName = selectedBaseName; int cnt = 0; while (!newNames.contains(selectedName) && abc.constants.getStringId(selectedName, false) > -1) { //already exists such name, but was not added during this collisionFixes cnt++; selectedName = selectedBaseName + "_" + cnt; } newNames.add(selectedName); int newNameIndex = abc.constants.getStringId(selectedName, true); multiName.name_index = newNameIndex; //Find other names with same name and namespace which are not listed as colliding, but are related for (int m = 1; m < abc.constants.getMultinameCount(); m++) { if (collidingMultinameIndices.contains(m)) { continue; } Multiname other = abc.constants.getMultiname(m); if (other.hasOwnName() && other.hasOwnNamespace()) { int otherNamespace = other.namespace_index; if (namespace == otherNamespace) { if (Objects.equals(oldName, abc.constants.getString(other.name_index))) { other.name_index = newNameIndex; ret++; } } } else if (other.hasOwnName() && other.hasOwnNamespaceSet()) { NamespaceSet otherNamespaceSet = abc.constants.getNamespaceSet(other.namespace_set_index); //NamespaceSet with only one namespace - this one if (otherNamespaceSet.namespaces.length == 1) { int otherNamespace = otherNamespaceSet.namespaces[0]; if (namespace == otherNamespace) { if (Objects.equals(oldName, abc.constants.getString(other.name_index))) { other.name_index = newNameIndex; ret++; } } } //What if there are more namespaces in the set and how about runtime resolved names? } } ret++; } if (ret > 0) { ((Tag) abc.parentTag).setModified(true); } return ret; } }