From cc90c225740ce35388d506e2b8e7cbe223581999 Mon Sep 17 00:00:00 2001 From: REAndroid Date: Sun, 1 Dec 2024 15:21:21 +0100 Subject: [PATCH] [DEX] Rework and simplify annotation handling --- .../reandroid/dex/common/AnnotatedItem.java | 31 +-- .../reandroid/dex/common/IdDefinition.java | 2 +- .../reandroid/dex/data/AnnotationElement.java | 2 +- .../reandroid/dex/data/AnnotationItem.java | 2 +- .../dex/data/AnnotationsDirectory.java | 66 ++---- src/main/java/com/reandroid/dex/data/Def.java | 31 --- .../reandroid/dex/data/MethodParameter.java | 23 +- .../java/com/reandroid/dex/id/ClassId.java | 206 +++++------------- .../dex/key/AnnotationElementKey.java | 16 +- .../reandroid/dex/key/AnnotationItemKey.java | 89 +++++++- .../reandroid/dex/key/AnnotationSetKey.java | 114 +++++++++- .../java/com/reandroid/dex/key/KeyList.java | 7 + .../com/reandroid/dex/model/AnnotatedDex.java | 19 +- .../com/reandroid/dex/model/DalvikUtil.java | 3 +- .../reandroid/dex/model/DexAnnotation.java | 203 ++++++++++++----- .../dex/model/DexAnnotationElement.java | 111 ++++++++-- .../com/reandroid/dex/model/DexClass.java | 95 ++------ .../reandroid/dex/model/DexDeclaration.java | 51 +++-- .../com/reandroid/dex/model/DexField.java | 39 ---- .../com/reandroid/dex/model/DexMethod.java | 43 +--- .../dex/model/DexMethodParameter.java | 76 +++---- .../com/reandroid/dex/model/RClassParent.java | 77 +++---- .../smali/model/SmaliAnnotationElement.java | 2 +- .../dex/smali/model/SmaliAnnotationItem.java | 2 +- 24 files changed, 661 insertions(+), 649 deletions(-) diff --git a/src/main/java/com/reandroid/dex/common/AnnotatedItem.java b/src/main/java/com/reandroid/dex/common/AnnotatedItem.java index 62b0bd92e..c368f2b3f 100644 --- a/src/main/java/com/reandroid/dex/common/AnnotatedItem.java +++ b/src/main/java/com/reandroid/dex/common/AnnotatedItem.java @@ -20,7 +20,6 @@ import com.reandroid.dex.key.Key; import com.reandroid.dex.key.TypeKey; -import java.util.Iterator; import java.util.function.Predicate; public interface AnnotatedItem { @@ -31,7 +30,6 @@ public interface AnnotatedItem { default void addAnnotation(AnnotationItemKey annotation) { AnnotationSetKey key = getAnnotation() - .remove(annotation.getType()) .add(annotation); setAnnotation(key); } @@ -45,30 +43,25 @@ default boolean removeAnnotationIf(Predicate predicat return true; } - default Iterator getAnnotations() { - return getAnnotation().iterator(); - } default boolean hasAnnotations() { return !getAnnotation().isEmpty(); } + default boolean hasAnnotation(TypeKey typeKey) { + return getAnnotation(typeKey) != null; + } default AnnotationItemKey getAnnotation(TypeKey typeKey) { - Iterator iterator = getAnnotations(); - while (iterator.hasNext()) { - AnnotationItemKey key = iterator.next(); - if (typeKey.equals(key.getType())) { - return key; - } - } - return null; + return getAnnotation().get(typeKey); } default Key getAnnotationValue(TypeKey typeKey, String name) { - AnnotationItemKey annotationItemKey = getAnnotation(typeKey); - if (annotationItemKey != null) { - return annotationItemKey.get(name); - } - return null; + return getAnnotation().getAnnotationValue(typeKey, name); } default boolean removeAnnotation(TypeKey typeKey) { - return removeAnnotationIf(key -> key.equalsType(typeKey)); + AnnotationSetKey annotation = getAnnotation(); + AnnotationSetKey update = annotation.remove(typeKey); + if (annotation.equals(update)) { + return false; + } + setAnnotation(update); + return true; } } diff --git a/src/main/java/com/reandroid/dex/common/IdDefinition.java b/src/main/java/com/reandroid/dex/common/IdDefinition.java index 2b2e2bb6a..f4f340fd6 100644 --- a/src/main/java/com/reandroid/dex/common/IdDefinition.java +++ b/src/main/java/com/reandroid/dex/common/IdDefinition.java @@ -20,7 +20,7 @@ import java.util.Iterator; -public interface IdDefinition { +public interface IdDefinition extends AnnotatedItem { T getId(); int getAccessFlagsValue(); Iterator getAccessFlags(); diff --git a/src/main/java/com/reandroid/dex/data/AnnotationElement.java b/src/main/java/com/reandroid/dex/data/AnnotationElement.java index 6c2fdf9ee..1dbfbce31 100644 --- a/src/main/java/com/reandroid/dex/data/AnnotationElement.java +++ b/src/main/java/com/reandroid/dex/data/AnnotationElement.java @@ -48,7 +48,7 @@ public AnnotationElement() { @Override public AnnotationElementKey getKey(){ - return new AnnotationElementKey(getName(), getValue()); + return AnnotationElementKey.create(getName(), getValue()); } @Override public void setKey(Key key) { diff --git a/src/main/java/com/reandroid/dex/data/AnnotationItem.java b/src/main/java/com/reandroid/dex/data/AnnotationItem.java index e6ce70263..50d36ce80 100644 --- a/src/main/java/com/reandroid/dex/data/AnnotationItem.java +++ b/src/main/java/com/reandroid/dex/data/AnnotationItem.java @@ -156,7 +156,7 @@ public String[] getNames(){ } @Override public AnnotationItemKey getKey(){ - return checkKey(new AnnotationItemKey(getVisibility(), getType(), getElements())); + return checkKey(AnnotationItemKey.create(getVisibility(), getType(), getElements())); } @Override public void setKey(Key key){ diff --git a/src/main/java/com/reandroid/dex/data/AnnotationsDirectory.java b/src/main/java/com/reandroid/dex/data/AnnotationsDirectory.java index 88d7ea6f1..7d5e3b8a5 100644 --- a/src/main/java/com/reandroid/dex/data/AnnotationsDirectory.java +++ b/src/main/java/com/reandroid/dex/data/AnnotationsDirectory.java @@ -87,7 +87,21 @@ public void setClassAnnotations(AnnotationSetKey setKey) { public AnnotationSet getOrCreateClassAnnotations(){ return header.classAnnotation.getOrCreate(); } - public AnnotationSet getClassAnnotations(){ + public AnnotationSetKey getClassAnnotation() { + AnnotationSetKey key = (AnnotationSetKey) header.classAnnotation.getKey(); + if (key == null) { + key = AnnotationSetKey.EMPTY; + } + return key; + } + public boolean hasClassAnnotation() { + AnnotationSet annotationSet = header.classAnnotation.getItem(); + if (annotationSet != null) { + return !annotationSet.isEmpty(); + } + return false; + } + public AnnotationSet getClassAnnotationBlock() { return header.classAnnotation.getItem(); } public void setClassAnnotations(AnnotationSet annotationSet){ @@ -99,20 +113,12 @@ public void setClassAnnotations(AnnotationSet annotationSet){ public boolean isBlank() { return isEmpty(); } - public boolean isEmpty(){ - return getClassAnnotations() == null && + public boolean isEmpty() { + return !hasClassAnnotation() && fieldsAnnotationMap.isEmpty() && methodsAnnotationMap.isEmpty() && parametersAnnotationMap.isEmpty(); } - public int countField(){ - return fieldsAnnotationMap.getCount() ; - } - public int countMethod(){ - return methodsAnnotationMap.getCount() + - parametersAnnotationMap.getCount(); - } - public void sortFields() { fieldsAnnotationMap.sort(); @@ -187,21 +193,12 @@ public Iterator getAnnotations(Def def){ public Iterator getFieldsAnnotation(FieldDef fieldDef){ return fieldsAnnotationMap.getValues(fieldDef); } - public Iterator getFieldsAnnotation(int index){ - return fieldsAnnotationMap.getValues(index); - } - public Iterator getMethodAnnotation(int index){ - return methodsAnnotationMap.getValues(index); - } public Iterator getMethodAnnotation(MethodDef methodDef){ return methodsAnnotationMap.getValues(methodDef); } public Iterator getParameterAnnotation(MethodDef methodDef){ return parametersAnnotationMap.getValues(methodDef); } - public Iterator> getParameterEntries(MethodDef methodDef){ - return parametersAnnotationMap.getEntries(methodDef); - } public Iterator getParameterAnnotation(int methodIndex){ return parametersAnnotationMap.getValues(methodIndex); } @@ -213,28 +210,9 @@ public Iterator getParameterAnnotation(int methodIndex, int param return ComputeIterator.of(getParameterAnnotation(methodIndex), annotationGroup -> annotationGroup.getItem(parameterIndex)); } - public AnnotationSet getOrCreateParameterAnnotation(MethodDef methodDef, int parameterIndex){ - AnnotationGroup annotationGroup = getOrCreateParameterAnnotationGroup(methodDef); - return annotationGroup.getOrCreateAt(parameterIndex); - } - private AnnotationGroup getOrCreateParameterAnnotationGroup(MethodDef methodDef){ - AnnotationGroup annotationGroup; - Iterator iterator = parametersAnnotationMap.getValues(methodDef); - if(iterator.hasNext()){ - annotationGroup = iterator.next(); - }else { - annotationGroup = getOrCreateSection(SectionType.ANNOTATION_GROUP).createItem(); - this.parametersAnnotationMap.add(methodDef, annotationGroup); - } - return annotationGroup; - } - public AnnotationSet createNewParameterAnnotation(MethodDef methodDef, int parameterIndex){ - AnnotationGroup annotationGroup = getEmptyParameterAnnotationGroup(methodDef, parameterIndex); - return annotationGroup.getOrCreateAt(parameterIndex); - } - public AnnotationSet setParameterAnnotation(MethodDef methodDef, int parameterIndex, AnnotationSetKey key){ + public void setParameterAnnotation(MethodDef methodDef, int parameterIndex, AnnotationSetKey key) { AnnotationGroup annotationGroup = getEmptyParameterAnnotationGroup(methodDef, parameterIndex); - return annotationGroup.setItemKeyAt(parameterIndex, key); + annotationGroup.setItemKeyAt(parameterIndex, key); } public void removeParameterAnnotation(MethodDef methodDef, int parameterIndex) { Iterator iterator = parametersAnnotationMap.getValues(methodDef); @@ -245,7 +223,7 @@ public void removeParameterAnnotation(MethodDef methodDef, int parameterIndex) { } } } - private AnnotationGroup getEmptyParameterAnnotationGroup(MethodDef methodDef, int parameterIndex){ + private AnnotationGroup getEmptyParameterAnnotationGroup(MethodDef methodDef, int parameterIndex) { Iterator iterator = parametersAnnotationMap.getValues(methodDef); while (iterator.hasNext()){ AnnotationGroup group = iterator.next(); @@ -259,7 +237,7 @@ private AnnotationGroup getEmptyParameterAnnotationGroup(MethodDef methodDef, in } public void replaceKeys(Key search, Key replace){ - AnnotationSet set = getClassAnnotations(); + AnnotationSet set = getClassAnnotationBlock(); if(set != null){ set.replaceKeys(search, replace); } @@ -285,7 +263,7 @@ public void editInternal(Block user) { } public Iterator usedIds(){ - AnnotationSet classAnnotation = getClassAnnotations(); + AnnotationSet classAnnotation = getClassAnnotationBlock(); Iterator iterator1; if(classAnnotation == null){ iterator1 = EmptyIterator.of(); diff --git a/src/main/java/com/reandroid/dex/data/Def.java b/src/main/java/com/reandroid/dex/data/Def.java index 0d4879d5d..58d5b9095 100644 --- a/src/main/java/com/reandroid/dex/data/Def.java +++ b/src/main/java/com/reandroid/dex/data/Def.java @@ -181,27 +181,6 @@ public void setKey(Key key){ setItem(key); } - public AnnotationSet getOrCreateAnnotationSet(){ - AnnotationSet annotationSet = CollectionUtil.getFirst(getAnnotationSets()); - if(annotationSet != null){ - return annotationSet; - } - AnnotationsDirectory directory = getOrCreateUniqueAnnotationsDirectory(); - annotationSet = directory.createSectionItem(SectionType.ANNOTATION_SET); - directory.addAnnotation(this, annotationSet); - return annotationSet; - } - public void addAnnotationSet(AnnotationSetKey key) { - AnnotationSet annotationSet = getOrCreateSectionItem(SectionType.ANNOTATION_SET, key); - addAnnotationSet(annotationSet); - } - public void addAnnotationSet(AnnotationSet annotationSet){ - AnnotationsDirectory directory = getOrCreateUniqueAnnotationsDirectory(); - addAnnotationSet(directory, annotationSet); - } - void addAnnotationSet(AnnotationsDirectory directory, AnnotationSet annotationSet){ - directory.addAnnotation(this, annotationSet); - } public Iterator getAnnotationKeys() { Iterator iterator = getAnnotationSetKeys(); if (!iterator.hasNext()) { @@ -217,9 +196,6 @@ public Iterator iterator(AnnotationSetKey element) { public Iterator getAnnotationSetKeys() { return ComputeIterator.of(getAnnotationSets(true), AnnotationSet::getKey); } - public Iterator getAnnotationSets() { - return getAnnotationSets(false); - } public Iterator getAnnotationSets(boolean skipEmpty){ AnnotationsDirectory directory = getAnnotationsDirectory(); if(directory == null) { @@ -245,13 +221,6 @@ public AnnotationsDirectory getOrCreateUniqueAnnotationsDirectory(){ } return null; } - public AnnotationsDirectory getUniqueAnnotationsDirectory(){ - ClassId classId = getClassId(); - if(classId != null){ - return classId.getUniqueAnnotationsDirectory(); - } - return null; - } public ClassId getClassId() { DefArray> array = getParentArray(); if(array != null){ diff --git a/src/main/java/com/reandroid/dex/data/MethodParameter.java b/src/main/java/com/reandroid/dex/data/MethodParameter.java index 92151495a..0c2f60c8c 100644 --- a/src/main/java/com/reandroid/dex/data/MethodParameter.java +++ b/src/main/java/com/reandroid/dex/data/MethodParameter.java @@ -74,7 +74,7 @@ private boolean hasAnnotationSetBlocks() { return false; } - public Iterator getAnnotationItemBlocks() { + private Iterator getAnnotationItemBlocks() { MethodDef methodDef = getMethodDef(); AnnotationsDirectory directory = methodDef.getAnnotationsDirectory(); if (directory != null) { @@ -84,31 +84,18 @@ public Iterator getAnnotationItemBlocks() { return EmptyIterator.of(); } - public AnnotationItem addAnnotationItemBlock(TypeKey typeKey) { - return getOrCreateAnnotationSet().addNewItem(typeKey); - } - - public AnnotationItem getOrCreateAnnotationItemBlock(TypeKey typeKey) { - return getOrCreateAnnotationSet().getOrCreate(typeKey); - } - - - public AnnotationSet getOrCreateAnnotationSet() { - MethodDef methodDef = getMethodDef(); - AnnotationsDirectory directory = methodDef.getOrCreateUniqueAnnotationsDirectory(); - return directory.getOrCreateParameterAnnotation(methodDef, getDefinitionIndex()); - } - private void writeAnnotation(AnnotationSetKey key) { MethodDef methodDef = getMethodDef(); + int index = getDefinitionIndex(); if (key == null || key.isEmpty()) { if (hasAnnotationSetBlocks()) { AnnotationsDirectory directory = methodDef.getOrCreateUniqueAnnotationsDirectory(); - directory.removeParameterAnnotation(methodDef, getDefinitionIndex()); + directory.removeParameterAnnotation(methodDef, index); } } else { AnnotationsDirectory directory = methodDef.getOrCreateUniqueAnnotationsDirectory(); - directory.setParameterAnnotation(methodDef, getDefinitionIndex(), key); + directory.removeParameterAnnotation(methodDef, index); + directory.setParameterAnnotation(methodDef, index, key); } } diff --git a/src/main/java/com/reandroid/dex/id/ClassId.java b/src/main/java/com/reandroid/dex/id/ClassId.java index 0eed2c6b2..ce091108f 100644 --- a/src/main/java/com/reandroid/dex/id/ClassId.java +++ b/src/main/java/com/reandroid/dex/id/ClassId.java @@ -26,7 +26,6 @@ import com.reandroid.dex.sections.Section; import com.reandroid.dex.sections.SectionType; import com.reandroid.dex.smali.model.SmaliClass; -import com.reandroid.dex.value.*; import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.utils.StringsUtil; import com.reandroid.utils.collection.*; @@ -35,7 +34,7 @@ import java.util.Iterator; import java.util.Objects; -public class ClassId extends IdItem implements IdDefinition, AnnotatedItem, Comparable { +public class ClassId extends IdItem implements IdDefinition, Comparable { private final ClassTypeId classTypeId; private final IndirectInteger accessFlagValue; @@ -96,8 +95,11 @@ public void setKey(Key key){ @Override public AnnotationSetKey getAnnotation() { - return AnnotationSetKey.create( - ComputeIterator.of(getAnnotationItemBlocks(), AnnotationItem::getKey)); + AnnotationsDirectory directory = getAnnotationsDirectory(); + if (directory != null) { + return directory.getClassAnnotation(); + } + return AnnotationSetKey.EMPTY; } @Override public void setAnnotation(AnnotationSetKey annotationSet) { @@ -108,28 +110,21 @@ public void setAnnotation(AnnotationSetKey annotationSet) { public void clearAnnotations() { writeAnnotation(AnnotationSetKey.EMPTY); } - private boolean hasAnnotationSetBlocks() { - return getAnnotationItemBlocks().hasNext(); - } - private Iterator getAnnotationItemBlocks() { + @Override + public boolean hasAnnotations() { AnnotationsDirectory directory = getAnnotationsDirectory(); if (directory != null) { - AnnotationSet annotationSet = directory.getClassAnnotations(); - if (annotationSet != null) { - return annotationSet.iterator(); - } + return directory.hasClassAnnotation(); } - return EmptyIterator.of(); + return false; } private void writeAnnotation(AnnotationSetKey key) { if (key == null || key.isEmpty()) { - if (hasAnnotationSetBlocks()) { - AnnotationsDirectory directory = getOrCreateUniqueAnnotationsDirectory(); - directory.setClassAnnotations((AnnotationSetKey )null); + if (hasAnnotations()) { + getOrCreateUniqueAnnotationsDirectory().setClassAnnotations((AnnotationSetKey )null); } } else { - AnnotationsDirectory directory = getOrCreateUniqueAnnotationsDirectory(); - directory.setClassAnnotations(key); + getOrCreateUniqueAnnotationsDirectory().setClassAnnotations(key); } } public String getName(){ @@ -207,55 +202,33 @@ public void setInterfaces(TypeListKey typeListKey){ } public Key getDalvikEnclosing(){ - TypeValue typeValue = getDalvikEnclosingClass(); - if(typeValue != null){ - return typeValue.getKey(); + TypeKey typeKey = getDalvikEnclosingClass(); + if(typeKey != null) { + return typeKey; } - MethodIdValue methodIdValue = getDalvikEnclosingMethodId(); - if(methodIdValue != null){ - return methodIdValue.getKey(); + MethodKey enclosingMethod = getDalvikEnclosingMethod(); + if (enclosingMethod != null) { + return enclosingMethod.getDeclaring(); } return null; } - public MethodIdValue getDalvikEnclosingMethodId(){ - AnnotationItem annotationItem = getDalvikEnclosingMethod(); - if(annotationItem != null){ - DexValueBlock value = annotationItem.getElementValue(Key.DALVIK_value); - if(value instanceof MethodIdValue){ - return (MethodIdValue) value; - } - } - return null; - } - public Iterator getMemberClassKeys(){ - return ComputeIterator.of(getDalvikMemberClasses(), TypeValue::getKey); - } - public Iterator getDalvikMemberClasses(){ - AnnotationItem annotationItem = getDalvikMemberClass(); - if(annotationItem != null){ - DexValueBlock value = annotationItem.getElementValue(Key.DALVIK_value); - if(value instanceof ArrayValue){ - return ((ArrayValue)value).iterator(TypeValue.class); - } + public Iterator getDalvikMemberClasses() { + Key key = getAnnotationValue(TypeKey.DALVIK_MemberClass, Key.DALVIK_value); + if (key instanceof KeyList) { + return ((KeyList) key).iterator(TypeKey.class); } return EmptyIterator.of(); } - public AnnotationItem getDalvikEnclosingMethod(){ - return getClassAnnotation(TypeKey.DALVIK_EnclosingMethod); - } - public AnnotationItem getDalvikMemberClass(){ - return getClassAnnotation(TypeKey.DALVIK_MemberClass); - } - public AnnotationItem getDalvikInnerClass(){ - AnnotationSet annotationSet = getClassAnnotations(); - if(annotationSet == null){ - return null; + public MethodKey getDalvikEnclosingMethod() { + Key key = getAnnotationValue(TypeKey.DALVIK_EnclosingMethod, Key.DALVIK_value); + if (key instanceof MethodKey) { + return (MethodKey) key; } - return annotationSet.get(TypeKey.DALVIK_InnerClass); + return null; } - public AnnotationItem getOrCreateDalvikInnerClass(){ + public AnnotationItemKey getOrCreateDalvikInnerClass(){ TypeKey typeKey = getKey(); - if(typeKey == null){ + if (typeKey == null) { return null; } String inner = typeKey.getSimpleInnerName(); @@ -266,26 +239,16 @@ public AnnotationItem getOrCreateDalvikInnerClass(){ } return getOrCreateDalvikInnerClass(getAccessFlagsValue(), inner); } - public AnnotationItem getOrCreateDalvikInnerClass(int flags, String name){ - AnnotationSet annotationSet = getOrCreateClassAnnotations(); - AnnotationItem item = annotationSet.getOrCreate(TypeKey.DALVIK_InnerClass); - item.setVisibility(AnnotationVisibility.SYSTEM); - - AnnotationElement accessFlags = item.getOrCreateElement(Key.DALVIK_accessFlags); - IntValue accessFlagsValue = accessFlags.getOrCreateValue(DexValueType.INT); - accessFlagsValue.set(flags); - - AnnotationElement nameElement = item.getOrCreateElement(Key.DALVIK_name); - - if(name != null){ - StringValue stringValue = nameElement.getOrCreateValue(DexValueType.STRING); - stringValue.setKey(new StringKey(name)); - }else { - nameElement.getOrCreateValue(DexValueType.NULL); - } - return item; + public AnnotationItemKey getOrCreateDalvikInnerClass(int flags, String name) { + AnnotationItemKey itemKey = AnnotationItemKey.create(AnnotationVisibility.SYSTEM, + TypeKey.DALVIK_InnerClass) + .add(Key.DALVIK_accessFlags, PrimitiveKey.of(flags)) + .add(Key.DALVIK_name, name == null ? NullValueKey.INSTANCE : StringKey.create(name)); + AnnotationSetKey annotation = getAnnotation().add(itemKey); + setAnnotation(annotation); + return itemKey; } - public TypeValue getOrCreateDalvikEnclosingClass(){ + public TypeKey getOrCreateDalvikEnclosingClass(){ TypeKey key = getKey(); if(key != null){ TypeKey enclosing = key.getEnclosingClass(); @@ -295,89 +258,24 @@ public TypeValue getOrCreateDalvikEnclosingClass(){ } return null; } - public TypeValue getOrCreateDalvikEnclosingClass(TypeKey enclosing){ - if(enclosing == null){ - return null; - } - AnnotationSet annotationSet = getOrCreateClassAnnotations(); - AnnotationItem item = annotationSet.getOrCreate(TypeKey.DALVIK_EnclosingClass); - item.setVisibility(AnnotationVisibility.SYSTEM); - AnnotationElement element = item.getOrCreateElement(Key.DALVIK_value); - TypeValue typeValue = element.getOrCreateValue(DexValueType.TYPE); - typeValue.setKey(enclosing); - return typeValue; - } - public TypeValue getDalvikEnclosingClass(){ - AnnotationItem item = getDalvikEnclosingClassAnnotation(); - if(item == null){ + public TypeKey getOrCreateDalvikEnclosingClass(TypeKey enclosing) { + if (enclosing == null) { return null; } - AnnotationElement element = item.getElement(Key.DALVIK_value); - DexValueBlock value = element.getValueBlock(); - if(value instanceof TypeValue){ - return (TypeValue) value; - } - return null; - } - public AnnotationItem getDalvikEnclosingClassAnnotation(){ - AnnotationSet annotationSet = getClassAnnotations(); - if(annotationSet != null){ - return annotationSet.get(TypeKey.DALVIK_EnclosingClass); - } - return null; - } - public void setClassAnnotations(AnnotationSetKey setKey) { - AnnotationsDirectory directory = getAnnotationsDirectory(); - if (directory == null) { - if (setKey == null) { - return; - } - directory = getOrCreateAnnotationsDirectory(); - } - directory.setClassAnnotations(setKey); - } - public AnnotationSet getOrCreateClassAnnotations(){ - return getOrCreateAnnotationsDirectory().getOrCreateClassAnnotations(); + AnnotationItemKey itemKey = AnnotationItemKey.create(AnnotationVisibility.SYSTEM, + TypeKey.DALVIK_EnclosingClass) + .add(Key.DALVIK_value, enclosing); + AnnotationSetKey annotation = getAnnotation().add(itemKey); + setAnnotation(annotation); + return enclosing; } - public AnnotationItem getClassAnnotation(TypeKey typeKey){ - AnnotationSet classAnnotations = getClassAnnotations(); - if(classAnnotations != null){ - return classAnnotations.get(typeKey); + public TypeKey getDalvikEnclosingClass() { + Key key = getAnnotationValue(TypeKey.DALVIK_EnclosingClass, Key.DALVIK_value); + if (key instanceof TypeKey) { + return (TypeKey) key; } return null; } - public Iterator getClassAnnotations(TypeKey typeKey){ - AnnotationSet classAnnotations = getClassAnnotations(); - if(classAnnotations != null){ - return classAnnotations.getAll(typeKey); - } - return EmptyIterator.of(); - } - public AnnotationSetKey getAnnotationSetKey(){ - AnnotationSet annotationSet = getClassAnnotations(); - if (annotationSet != null) { - return annotationSet.getKey(); - } - return null; - } - public AnnotationSet getClassAnnotations(){ - AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory(); - if(annotationsDirectory != null){ - return annotationsDirectory.getClassAnnotations(); - } - return null; - } - public void setClassAnnotations(AnnotationSet annotationSet){ - AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory(); - if(annotationsDirectory != null){ - annotationsDirectory.setClassAnnotations(annotationSet); - } - } - public AnnotationsDirectory getOrCreateAnnotationsDirectory(){ - AnnotationsDirectory directory = annotationsDirectory.getOrCreate(); - directory.addUniqueUser(this); - return directory; - } public AnnotationsDirectory getUniqueAnnotationsDirectory(){ return annotationsDirectory.getUniqueItem(this); } @@ -570,7 +468,7 @@ public SmaliClass toSmali() { smaliClass.setSuperClass(getSuperClassKey()); smaliClass.setSourceFile(getSourceFile().getKey()); smaliClass.setInterfaces(getInterfacesReference().getKey()); - smaliClass.setAnnotation(getAnnotationSetKey()); + smaliClass.setAnnotation(getAnnotation()); ClassData classData = getClassData(); if (classData != null) { classData.toSmali(smaliClass); diff --git a/src/main/java/com/reandroid/dex/key/AnnotationElementKey.java b/src/main/java/com/reandroid/dex/key/AnnotationElementKey.java index b357840c6..d1ebc38d8 100644 --- a/src/main/java/com/reandroid/dex/key/AnnotationElementKey.java +++ b/src/main/java/com/reandroid/dex/key/AnnotationElementKey.java @@ -31,7 +31,7 @@ public class AnnotationElementKey implements Key { private final String name; private final Key value; - public AnnotationElementKey(String name, Key value) { + private AnnotationElementKey(String name, Key value) { this.name = name; this.value = value; } @@ -52,13 +52,13 @@ public AnnotationElementKey changeName(String name) { if (ObjectsUtil.equals(getName(), name)) { return this; } - return new AnnotationElementKey(name, getValue()); + return create(name, getValue()); } public AnnotationElementKey changeValue(Key value) { if (ObjectsUtil.equals(getValue(), value)) { return this; } - return new AnnotationElementKey(getName(), value); + return create(getName(), value); } @Override @@ -140,4 +140,14 @@ public void append(SmaliWriter writer) throws IOException { public String toString() { return getName() + " = " + getValue(); } + + public static AnnotationElementKey create(String name, Key value) { + if (name == null) { + return null; + } + if (value == null) { + value = NullValueKey.INSTANCE; + } + return new AnnotationElementKey(name, value); + } } diff --git a/src/main/java/com/reandroid/dex/key/AnnotationItemKey.java b/src/main/java/com/reandroid/dex/key/AnnotationItemKey.java index e4dd1e6d7..608d7f73e 100644 --- a/src/main/java/com/reandroid/dex/key/AnnotationItemKey.java +++ b/src/main/java/com/reandroid/dex/key/AnnotationItemKey.java @@ -29,13 +29,13 @@ public class AnnotationItemKey extends KeyList implements Key, Iterable { - private static final AnnotationElementKey[] EMPTY = new AnnotationElementKey[0]; + private static final AnnotationElementKey[] EMPTY_ARRAY = new AnnotationElementKey[0]; private final AnnotationVisibility visibility; private final TypeKey type; - public AnnotationItemKey(AnnotationVisibility visibility, TypeKey type, AnnotationElementKey[] elements) { - super(removeNulls(elements)); + private AnnotationItemKey(AnnotationVisibility visibility, TypeKey type, AnnotationElementKey[] elements) { + super(elements); this.visibility = visibility; this.type = type; } @@ -53,7 +53,41 @@ public AnnotationItemKey changeType(TypeKey typeKey) { if (typeKey.equals(getType())) { return this; } - return new AnnotationItemKey(getVisibility(), getType(), getElements()); + return create(getVisibility(), typeKey, getElements()); + } + public AnnotationItemKey remove(String name) { + return removeIf(elementKey -> ObjectsUtil.equals(elementKey.getName(), name)); + } + public AnnotationItemKey rename(String name, String newName) { + AnnotationItemKey result = this; + AnnotationElementKey elementKey = result.get(name); + if (elementKey == null) { + return result; + } + int i = result.indexOf(elementKey); + elementKey = elementKey.changeName(newName); + return result.set(i, elementKey).sorted(); + } + public AnnotationItemKey setValue(String name, Key value) { + AnnotationItemKey result = this; + result = result.getOrCreate(name); + AnnotationElementKey elementKey = result.get(name); + int i = result.indexOf(elementKey); + elementKey = elementKey.changeValue(value); + return result.set(i, elementKey); + } + public AnnotationItemKey getOrCreate(String name) { + AnnotationElementKey elementKey = get(name); + if (elementKey != null) { + return this; + } + return add(AnnotationElementKey.create(name, null)).sorted(); + } + public AnnotationItemKey changeVisibility(AnnotationVisibility visibility) { + if (ObjectsUtil.equals(getVisibility(), visibility)) { + return this; + } + return create(visibility, getType(), getElements()); } public AnnotationElementKey get(String name) { int size = size(); @@ -65,9 +99,37 @@ public AnnotationElementKey get(String name) { } return null; } + public Key getValue(String name) { + AnnotationElementKey element = get(name); + if (element != null) { + return element.getValue(); + } + return null; + } + public boolean containsElement(String name) { + int size = size(); + for (int i = 0; i < size; i++) { + AnnotationElementKey elementKey = get(i); + if (elementKey != null && ObjectsUtil.equals(name, elementKey.getName())) { + return true; + } + } + return false; + } + public AnnotationItemKey add(String name, Key value) { + return add(AnnotationElementKey.create(name, value)); + } @Override public AnnotationItemKey add(AnnotationElementKey item) { + if (item == null) { + return this; + } + return this.remove(item.getName()) + .addUnchecked(item) + .sorted(); + } + private AnnotationItemKey addUnchecked(AnnotationElementKey item) { return (AnnotationItemKey) super.add(item); } @Override @@ -86,15 +148,19 @@ public AnnotationItemKey removeIf(Predicate predic public AnnotationItemKey set(int i, AnnotationElementKey item) { return (AnnotationItemKey) super.set(i, item); } + @Override + public AnnotationItemKey sorted() { + return (AnnotationItemKey) super.sorted(); + } @Override AnnotationItemKey newInstance(AnnotationElementKey[] elements) { - return new AnnotationItemKey(getVisibility(), getType(), elements); + return create(getVisibility(), getType(), elements); } @Override AnnotationElementKey[] newArray(int length) { if (length == 0) { - return EMPTY; + return EMPTY_ARRAY; } return new AnnotationElementKey[length]; } @@ -198,6 +264,13 @@ public int hashCode() { return getHashCode(); } + public static AnnotationItemKey create(AnnotationVisibility visibility, TypeKey typeKey, AnnotationElementKey ... elements) { + if (typeKey == null) { + return null; + } + elements = removeNulls(elements); + return new AnnotationItemKey(visibility, typeKey, elements); + } public static AnnotationItemKey read(SmaliReader reader) throws IOException { //FIXME @@ -210,7 +283,7 @@ public static AnnotationItemKey parse(String text) { private static AnnotationElementKey[] removeNulls(AnnotationElementKey[] elements) { if (elements == null || elements.length == 0) { - return EMPTY; + return EMPTY_ARRAY; } int length = elements.length; int size = 0; @@ -224,7 +297,7 @@ private static AnnotationElementKey[] removeNulls(AnnotationElementKey[] element return elements; } if (size == 0) { - return EMPTY; + return EMPTY_ARRAY; } AnnotationElementKey[] results = new AnnotationElementKey[size]; int j = 0; diff --git a/src/main/java/com/reandroid/dex/key/AnnotationSetKey.java b/src/main/java/com/reandroid/dex/key/AnnotationSetKey.java index 936b6e5da..b462e89f0 100644 --- a/src/main/java/com/reandroid/dex/key/AnnotationSetKey.java +++ b/src/main/java/com/reandroid/dex/key/AnnotationSetKey.java @@ -15,13 +15,12 @@ */ package com.reandroid.dex.key; +import com.reandroid.dex.common.AnnotationVisibility; import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.utils.CompareUtil; import com.reandroid.utils.ObjectsUtil; import com.reandroid.utils.collection.ArrayCollection; import com.reandroid.utils.collection.ArraySort; -import com.reandroid.utils.collection.ComputeIterator; -import com.reandroid.utils.collection.SingleIterator; import java.io.IOException; import java.util.Iterator; @@ -35,17 +34,110 @@ public class AnnotationSetKey extends KeyList implements Key static { AnnotationItemKey[] emptyArray = new AnnotationItemKey[0]; EMPTY_ARRAY = emptyArray; - EMPTY = new AnnotationSetKey(emptyArray, false); + EMPTY = new AnnotationSetKey(emptyArray); } - private AnnotationSetKey(AnnotationItemKey[] elements, boolean unused) { + private AnnotationSetKey(AnnotationItemKey[] elements) { super(elements); } - private AnnotationSetKey(AnnotationItemKey[] elements) { - super(removeNulls(elements)); + public AnnotationSetKey removeElementIf(TypeKey typeKey, Predicate predicate) { + AnnotationSetKey result = this; + AnnotationItemKey itemKey = result.get(typeKey); + if (itemKey == null) { + return result; + } + int i = result.indexOf(itemKey); + itemKey = itemKey.removeIf(predicate); + return result.set(i, itemKey); + } + public AnnotationSetKey removeElement(TypeKey typeKey, String name) { + AnnotationSetKey result = this; + AnnotationItemKey itemKey = result.get(typeKey); + if (itemKey == null) { + return result; + } + int i = result.indexOf(itemKey); + itemKey = itemKey.remove(name); + return result.set(i, itemKey); + } + public AnnotationSetKey changeType(TypeKey typeKey, TypeKey newType) { + AnnotationSetKey result = this; + AnnotationItemKey itemKey = result.get(typeKey); + if (itemKey == null) { + return result; + } + int i = result.indexOf(itemKey); + itemKey = itemKey.changeType(newType); + return result.set(i, itemKey).sorted(); + } + public AnnotationSetKey renameElement(TypeKey typeKey, String name, String newName) { + AnnotationSetKey result = this; + AnnotationItemKey itemKey = result.get(typeKey); + if (itemKey == null) { + return result; + } + int i = result.indexOf(itemKey); + itemKey = itemKey.rename(name, newName); + return result.set(i, itemKey); + } + public AnnotationSetKey setAnnotation(TypeKey typeKey, String name, Key value) { + AnnotationSetKey result = this; + result = result.getOrCreate(typeKey); + AnnotationItemKey itemKey = result.get(typeKey); + int i = result.indexOf(itemKey); + itemKey = itemKey.setValue(name, value); + return result.set(i, itemKey); + } + public AnnotationSetKey getOrCreate(TypeKey typeKey, String name) { + AnnotationSetKey result = this; + result = result.getOrCreate(typeKey); + AnnotationItemKey itemKey = result.get(typeKey); + int i = result.indexOf(itemKey); + itemKey = itemKey.getOrCreate(name); + return result.set(i, itemKey); + } + public AnnotationSetKey setVisibility(TypeKey typeKey, AnnotationVisibility visibility) { + AnnotationItemKey itemKey = get(typeKey); + if (itemKey == null) { + return this; + } + int i = indexOf(itemKey); + itemKey = itemKey.changeVisibility(visibility); + return set(i, itemKey); + } + public AnnotationSetKey getOrCreate(TypeKey typeKey) { + AnnotationItemKey itemKey = get(typeKey); + if (itemKey != null) { + return this; + } + itemKey = AnnotationItemKey.create(AnnotationVisibility.BUILD, typeKey); + return this.add(itemKey).sorted(); + } + public Key getAnnotationValue(TypeKey typeKey, String name) { + AnnotationItemKey itemKey = get(typeKey); + if (itemKey != null) { + return itemKey.get(name); + } + return null; + } + public boolean containsElement(TypeKey typeKey, String name) { + AnnotationItemKey itemKey = get(typeKey); + if (itemKey != null) { + return itemKey.containsElement(name); + } + return false; + } + public boolean contains(TypeKey typeKey) { + int length = size(); + for (int i = 0; i < length; i++) { + AnnotationItemKey itemKey = get(i); + if (itemKey != null && ObjectsUtil.equals(typeKey, itemKey.getType())) { + return true; + } + } + return false; } - public AnnotationItemKey get(TypeKey typeKey) { int length = size(); for (int i = 0; i < length; i++) { @@ -59,6 +151,14 @@ public AnnotationItemKey get(TypeKey typeKey) { @Override public AnnotationSetKey add(AnnotationItemKey item) { + if (item == null) { + return this; + } + return this.remove(item.getType()) + .addUnchecked(item) + .sorted(); + } + private AnnotationSetKey addUnchecked(AnnotationItemKey item) { return (AnnotationSetKey) super.add(item); } @Override diff --git a/src/main/java/com/reandroid/dex/key/KeyList.java b/src/main/java/com/reandroid/dex/key/KeyList.java index 903f717d7..ad516dcf3 100644 --- a/src/main/java/com/reandroid/dex/key/KeyList.java +++ b/src/main/java/com/reandroid/dex/key/KeyList.java @@ -20,6 +20,7 @@ import com.reandroid.utils.ObjectsUtil; import com.reandroid.utils.collection.ArrayIterator; import com.reandroid.utils.collection.CombiningIterator; +import com.reandroid.utils.collection.InstanceIterator; import com.reandroid.utils.collection.IterableIterator; import java.io.IOException; @@ -50,6 +51,12 @@ public boolean isEmpty() { public Iterator iterator() { return ArrayIterator.of(this.elements); } + public Iterator iterator(Predicate predicate) { + return ArrayIterator.of(this.elements, predicate); + } + public Iterator iterator(Class instance) { + return InstanceIterator.of(iterator(), instance); + } public int indexOf(Object key) { T[] elements = this.elements; diff --git a/src/main/java/com/reandroid/dex/model/AnnotatedDex.java b/src/main/java/com/reandroid/dex/model/AnnotatedDex.java index 051523d98..3c9367818 100644 --- a/src/main/java/com/reandroid/dex/model/AnnotatedDex.java +++ b/src/main/java/com/reandroid/dex/model/AnnotatedDex.java @@ -15,42 +15,31 @@ */ package com.reandroid.dex.model; -import com.reandroid.dex.key.AnnotationItemKey; import com.reandroid.dex.key.Key; import com.reandroid.dex.key.TypeKey; -import java.lang.annotation.ElementType; import java.util.Iterator; public interface AnnotatedDex { Iterator getAnnotations(); - Iterator getAnnotations(TypeKey typeKey); DexAnnotation getAnnotation(TypeKey typeKey); - DexAnnotation getOrCreateAnnotation(AnnotationItemKey annotationItemKey); DexAnnotation getOrCreateAnnotation(TypeKey typeKey); - DexAnnotation newAnnotation(TypeKey typeKey); - - ElementType getElementType(); default DexAnnotationElement getAnnotationElement(TypeKey typeKey, String name){ DexAnnotation dexAnnotation = getAnnotation(typeKey); - if(dexAnnotation != null){ + if(dexAnnotation != null) { return dexAnnotation.get(name); } return null; } - default DexAnnotationElement getOrCreateAnnotationElement(TypeKey typeKey, String name){ - DexAnnotationElement element = getAnnotationElement(typeKey, name); - if(element != null){ - return element; - } + default DexAnnotationElement getOrCreateAnnotationElement(TypeKey typeKey, String name) { DexAnnotation annotation = getOrCreateAnnotation(typeKey); return annotation.getOrCreate(name); } - default Key getAnnotationValue(TypeKey typeKey, String name){ + default Key getAnnotationValue(TypeKey typeKey, String name) { DexAnnotationElement element = getAnnotationElement(typeKey, name); - if(element != null){ + if (element != null) { return element.getValue(); } return null; diff --git a/src/main/java/com/reandroid/dex/model/DalvikUtil.java b/src/main/java/com/reandroid/dex/model/DalvikUtil.java index 48fb77b58..64030e248 100644 --- a/src/main/java/com/reandroid/dex/model/DalvikUtil.java +++ b/src/main/java/com/reandroid/dex/model/DalvikUtil.java @@ -18,6 +18,7 @@ import com.reandroid.dex.key.ArrayKey; import com.reandroid.dex.key.Key; import com.reandroid.dex.key.TypeKey; +import com.reandroid.utils.collection.SingleIterator; import java.util.Iterator; @@ -33,7 +34,7 @@ public static int cleanMissingMembers(DexClassRepository repository) { } public static int cleanMissingMembers(DexClass dexClass) { int result = 0; - Iterator iterator = dexClass.getAnnotations(TypeKey.DALVIK_MemberClass); + Iterator iterator = SingleIterator.of(dexClass.getAnnotation(TypeKey.DALVIK_MemberClass)); while (iterator.hasNext()) { DexAnnotation annotation = iterator.next(); DexAnnotationElement element = annotation.get("value"); diff --git a/src/main/java/com/reandroid/dex/model/DexAnnotation.java b/src/main/java/com/reandroid/dex/model/DexAnnotation.java index ab0aa717f..30de41818 100644 --- a/src/main/java/com/reandroid/dex/model/DexAnnotation.java +++ b/src/main/java/com/reandroid/dex/model/DexAnnotation.java @@ -15,109 +15,200 @@ */ package com.reandroid.dex.model; +import com.reandroid.common.ArraySupplier; +import com.reandroid.dex.common.AnnotatedItem; import com.reandroid.dex.common.AnnotationVisibility; -import com.reandroid.dex.data.AnnotationItem; -import com.reandroid.dex.key.AnnotationItemKey; -import com.reandroid.dex.key.Key; -import com.reandroid.dex.key.TypeKey; +import com.reandroid.dex.key.*; import com.reandroid.dex.smali.SmaliWriter; -import com.reandroid.utils.collection.ComputeIterator; +import com.reandroid.utils.collection.ArraySupplierIterator; import java.io.IOException; +import java.lang.annotation.ElementType; import java.util.Iterator; public class DexAnnotation extends Dex implements Iterable{ private final Dex declaring; - private final AnnotationItem annotationItem; + private final AnnotatedItem annotatedItem; + private TypeKey typeKey; + private AnnotationItemKey mRemoved; - public DexAnnotation(Dex declaring, AnnotationItem annotationItem){ + public DexAnnotation(Dex declaring, AnnotatedItem annotatedItem, TypeKey typeKey){ super(); this.declaring = declaring; - this.annotationItem = annotationItem; + this.annotatedItem = annotatedItem; + this.typeKey = typeKey; } public AnnotationItemKey getKey() { - return getAnnotationItem().getKey(); + AnnotationItemKey key = this.mRemoved; + if (key == null) { + key = getAnnotationSet() + .get(getType()); + } + return key; } - public void setKey(AnnotationItemKey key) { - getAnnotationItem().setKey(key); + public void setKey(Key key) { + AnnotationItemKey itemKey = (AnnotationItemKey) key; + AnnotationSetKey annotationSetKey = getAnnotationSet() + .remove(getType()) + .add(itemKey); + setAnnotation(annotationSetKey); + this.typeKey = itemKey.getType(); } - public TypeKey getType(){ - return getAnnotationItem().getType(); + public TypeKey getType() { + return typeKey; } - public void setType(TypeKey typeKey){ - getAnnotationItem().setType(typeKey); + public void setType(TypeKey typeKey) { + setKey(getKey().changeType(typeKey)); } @Override public boolean uses(Key key) { - return getAnnotationItem().uses(key); + return getKey().uses(key); } - public boolean contains(String name){ - return getAnnotationItem().containsName(name); + public boolean contains(String name) { + return getKey().containsElement(name); + } + public DexAnnotationElement get(String name) { + return DexAnnotationElement.create(this, name); } - public DexAnnotationElement get(String name){ - return DexAnnotationElement.create(this, - getAnnotationItem().getElement(name)); + public DexAnnotationElement get(int index) { + return DexAnnotationElement.create(this, getKey().get(index)); } - public DexAnnotationElement get(int index){ - return DexAnnotationElement.create(this, - getAnnotationItem().getElement(index)); + public int size() { + return getKey().size(); } - public int size(){ - return getAnnotationItem().getElementsCount(); + public void remove(String name) { + setKey(getKey().remove(name)); } @Override public Iterator iterator() { - return ComputeIterator.of( - getAnnotationItem().iterator(), - element -> DexAnnotationElement.create( - DexAnnotation.this, element) - ); - } - public Iterator clonedIterator() { - return ComputeIterator.of( - getAnnotationItem().clonedIterator(), - element -> DexAnnotationElement.create( - DexAnnotation.this, element) - ); - } - public AnnotationVisibility getVisibility(){ - return getAnnotationItem().getVisibility(); + return ArraySupplierIterator.of(new ArraySupplier() { + @Override + public DexAnnotationElement get(int i) { + return DexAnnotation.this.get(i); + } + @Override + public int getCount() { + return DexAnnotation.this.size(); + } + }); + } + public AnnotationVisibility getVisibility() { + return getKey().getVisibility(); + } + public void setVisibility(AnnotationVisibility visibility) { + setKey(getKey().changeVisibility(visibility)); + } + public DexAnnotationElement getOrCreate(String name) { + if (!contains(name)) { + setKey(getKey().getOrCreate(name)); + } + return DexAnnotationElement.create(this, name); } - public void setVisibility(AnnotationVisibility visibility){ - getAnnotationItem().setVisibility(visibility); + @Override + public void removeSelf() { + if (!isRemoved()) { + applyRemoveSelf(); + } } - public DexAnnotationElement getOrCreate(String name){ - return DexAnnotationElement.create(this, - getAnnotationItem().getOrCreateElement(name)); + public boolean isRemoved() { + checkRemoved(); + return this.typeKey == null; + } + private void checkRemoved() { + AnnotationItemKey key = this.mRemoved; + if (key != null) { + AnnotationSetKey annotationSetKey = getAnnotationSet(); + TypeKey typeKey = key.getType(); + if (annotationSetKey != null) { + if (annotationSetKey.contains(typeKey)) { + this.typeKey = typeKey; + this.mRemoved = null; + } else { + applyRemoveSelf(); + } + } + } } - @Override - public void removeSelf(){ - getAnnotationItem().removeSelf(); + private void applyRemoveSelf() { + AnnotationItemKey key = this.mRemoved; + if (key != null) { + this.typeKey = null; + return; + } + AnnotationSetKey annotationSetKey = getAnnotationSet(); + key = getKey(); + TypeKey typeKey = this.typeKey; + this.typeKey = null; + if (key != null) { + this.mRemoved = key; + typeKey = key.getType(); + } + setAnnotation(annotationSetKey.remove(typeKey)); } - public AnnotationItem getAnnotationItem() { - return annotationItem; - } public Dex getDeclaring() { return declaring; } + private AnnotatedItem getAnnotatedItem() { + return annotatedItem; + } + private AnnotationSetKey getAnnotationSet() { + return getAnnotatedItem().getAnnotation(); + } + private void setAnnotation(AnnotationSetKey annotationSetKey) { + getAnnotatedItem().setAnnotation(annotationSetKey); + } + + + public ElementType getAnnotationType() { + Dex declaring = getDeclaring(); + if (declaring instanceof DexMethodParameter) { + return ElementType.PARAMETER; + } + if (declaring instanceof DexMethod) { + return ElementType.METHOD; + } + if (declaring instanceof DexField) { + return ElementType.FIELD; + } + return ElementType.TYPE; + } + @Override public DexClassRepository getClassRepository() { return getDeclaring().getClassRepository(); } + @Override public void append(SmaliWriter writer) throws IOException { - getAnnotationItem().append(writer); + if (!isRemoved()) { + getKey().append(writer); + } + } + @Override + public String toString() { + AnnotationItemKey key = getKey(); + if (isRemoved()) { + return "#REMOVED " + key; + } + return String.valueOf(key); + } + + public static DexAnnotation create(Dex declaring, AnnotatedItem annotatedItem, TypeKey typeKey) { + if(declaring != null && annotatedItem != null && annotatedItem.hasAnnotation(typeKey)) { + return new DexAnnotation(declaring, annotatedItem, typeKey); + } + return null; } - public static DexAnnotation create(Dex declaring, AnnotationItem annotationItem){ - if(declaring != null && annotationItem != null){ - return new DexAnnotation(declaring, annotationItem); + public static DexAnnotation create(Dex declaring, AnnotatedItem annotatedItem, AnnotationItemKey itemKey) { + if(declaring != null && annotatedItem != null && itemKey != null) { + return create(declaring, annotatedItem, itemKey.getType()); } return null; } diff --git a/src/main/java/com/reandroid/dex/model/DexAnnotationElement.java b/src/main/java/com/reandroid/dex/model/DexAnnotationElement.java index 56837563d..f0331f061 100644 --- a/src/main/java/com/reandroid/dex/model/DexAnnotationElement.java +++ b/src/main/java/com/reandroid/dex/model/DexAnnotationElement.java @@ -15,8 +15,7 @@ */ package com.reandroid.dex.model; -import com.reandroid.dex.data.AnnotationElement; -import com.reandroid.dex.key.Key; +import com.reandroid.dex.key.*; import com.reandroid.dex.smali.SmaliWriter; import java.io.IOException; @@ -24,35 +23,90 @@ public class DexAnnotationElement extends Dex { private final DexAnnotation dexAnnotation; - private final AnnotationElement annotationElement; + private String name; + private AnnotationElementKey mRemoved; - public DexAnnotationElement(DexAnnotation dexAnnotation, AnnotationElement annotationElement){ + public DexAnnotationElement(DexAnnotation dexAnnotation, String name) { super(); this.dexAnnotation = dexAnnotation; - this.annotationElement = annotationElement; + this.name = name; } public String getName(){ - return getAnnotationElement().getName(); + return name; } - public void setName(String name){ - getAnnotationElement().setName(name); + public void setName(String name) { + setKey(getKey().changeName(name)); + } + public AnnotationElementKey getKey() { + AnnotationElementKey key = this.mRemoved; + if (key == null) { + key = getDexAnnotation() + .getKey() + .get(getName()); + } + return key; + } + public void setKey(Key key) { + AnnotationElementKey elementKey = (AnnotationElementKey) key; + DexAnnotation annotation = getDexAnnotation(); + AnnotationItemKey itemKey = annotation.getKey() + .remove(getName()) + .add(elementKey); + annotation.setKey(itemKey); + this.name = elementKey.getName(); } - public Key getValue(){ - return getAnnotationElement().getValue(); + public Key getValue() { + return getKey().getValue(); } public void setValue(Key value) { - getAnnotationElement().setValue(value); + setKey(getKey().changeValue(value)); } @Override - public void removeSelf(){ - getAnnotationElement().removeSelf(); + public void removeSelf() { + if (!isRemoved()) { + applyRemoveSelf(); + } + } + public boolean isRemoved() { + checkRemoved(); + return this.name == null; + } + private void checkRemoved() { + DexAnnotation annotation = getDexAnnotation(); + if (annotation.isRemoved()) { + applyRemoveSelf(); + return; + } + AnnotationElementKey key = this.mRemoved; + if (key != null) { + if (!annotation.isRemoved()) { + String name = key.getName(); + if (annotation.contains(key.getName())) { + this.name = name; + this.mRemoved = null; + } + } + } + } + private void applyRemoveSelf() { + AnnotationElementKey key = this.mRemoved; + if (key != null) { + this.name = null; + return; + } + key = getKey(); + this.name = null; + if (key != null) { + this.mRemoved = key; + getDexAnnotation().remove(key.getName()); + } } - public AnnotationElement getAnnotationElement() { - return annotationElement; + public TypeKey getType() { + return getDexAnnotation().getType(); } public DexAnnotation getDexAnnotation() { return dexAnnotation; @@ -60,7 +114,7 @@ public DexAnnotation getDexAnnotation() { @Override public boolean uses(Key key) { - return getAnnotationElement().uses(key); + return getKey().uses(key); } @Override @@ -70,12 +124,29 @@ public DexClassRepository getClassRepository() { @Override public void append(SmaliWriter writer) throws IOException { - getAnnotationElement().append(writer); + if (!isRemoved()) { + getKey().append(writer); + } } - public static DexAnnotationElement create(DexAnnotation dexAnnotation, AnnotationElement annotationElement){ - if(dexAnnotation != null && annotationElement != null){ - return new DexAnnotationElement(dexAnnotation, annotationElement); + @Override + public String toString() { + AnnotationElementKey key = getKey(); + if (isRemoved()) { + return "#REMOVED " + key; + } + return String.valueOf(key); + } + + public static DexAnnotationElement create(DexAnnotation dexAnnotation, String name) { + if(dexAnnotation != null && name != null) { + return new DexAnnotationElement(dexAnnotation, name); + } + return null; + } + public static DexAnnotationElement create(DexAnnotation dexAnnotation, AnnotationElementKey elementKey) { + if (dexAnnotation != null && elementKey != null) { + return create(dexAnnotation, elementKey.getName()); } return null; } diff --git a/src/main/java/com/reandroid/dex/model/DexClass.java b/src/main/java/com/reandroid/dex/model/DexClass.java index 3aca3c675..3bc6137eb 100644 --- a/src/main/java/com/reandroid/dex/model/DexClass.java +++ b/src/main/java/com/reandroid/dex/model/DexClass.java @@ -25,21 +25,17 @@ import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.dex.smali.model.SmaliField; import com.reandroid.dex.smali.model.SmaliMethod; -import com.reandroid.dex.value.DexValueBlock; -import com.reandroid.dex.value.DexValueType; -import com.reandroid.dex.value.NullValue; -import com.reandroid.dex.value.StringValue; import com.reandroid.utils.collection.*; import com.reandroid.utils.io.FileUtil; import java.io.*; -import java.lang.annotation.ElementType; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.function.Predicate; public class DexClass extends DexDeclaration implements Comparable { + private final DexLayout dexLayout; private final ClassId classId; @@ -453,40 +449,24 @@ public void clearDebug(){ iterator.next().clearDebug(); } } - public void removeAnnotations(Predicate filter) { - ClassId classId = getId(); - AnnotationSet annotationSet = classId.getClassAnnotations(); - if(annotationSet == null) { + public void fixDalvikInnerClassName() { + DexAnnotation annotation = getAnnotation(TypeKey.DALVIK_InnerClass); + if (annotation == null) { return; } - annotationSet.removeIf(filter); - annotationSet.refresh(); - if(annotationSet.size() == 0){ - annotationSet.removeSelf(); - classId.setClassAnnotations((AnnotationSet) null); - } - getId().refresh(); - } - public void fixDalvikInnerClassName(){ - AnnotationItem annotationItem = getId().getDalvikInnerClass(); - if(annotationItem == null){ + DexAnnotationElement element = annotation.get(Key.DALVIK_name); + if (element == null) { return; } - AnnotationElement element = annotationItem.getElement("name"); - if(element == null){ - return; - } - DexValueBlock valueBlock = element.getValueBlock(); - if(!valueBlock.is(DexValueType.STRING)){ + if (!(element.getValue() instanceof StringKey)) { return; } TypeKey typeKey = getKey(); - if(!typeKey.isInnerName()){ - element.setValue(new NullValue()); - return; + if (!typeKey.isInnerName()) { + element.setValue(NullValueKey.INSTANCE); + } else { + element.setValue(StringKey.create(typeKey.getSimpleInnerName())); } - StringValue value = (StringValue) valueBlock; - value.setString(typeKey.getSimpleInnerName()); } public Set fixAccessibility(){ DexClassRepository repository = getClassRepository(); @@ -544,65 +524,23 @@ public TypeKey getDalvikEnclosingClass(){ return null; } public String getDalvikInnerClassName(){ - Key key = getAnnotationValue(TypeKey.DALVIK_InnerClass, "name"); + Key key = getAnnotationValue(TypeKey.DALVIK_InnerClass, Key.DALVIK_name); if(key instanceof StringKey){ return ((StringKey) key).getString(); } return null; } public void updateDalvikInnerClassName(String name){ - DexAnnotationElement element = getAnnotationElement(TypeKey.DALVIK_InnerClass, "name"); + DexAnnotationElement element = getAnnotationElement(TypeKey.DALVIK_InnerClass, Key.DALVIK_name); if (element != null) { element.setValue(StringKey.create(name)); } } public void createDalvikInnerClassName(String name){ - DexAnnotationElement element = getOrCreateAnnotationElement(TypeKey.DALVIK_InnerClass, "name"); + DexAnnotationElement element = getOrCreateAnnotationElement(TypeKey.DALVIK_InnerClass, Key.DALVIK_name); element.setValue(StringKey.create(name)); } - @Override - public Iterator getAnnotations(){ - AnnotationSet annotationSet = getId().getClassAnnotations(); - if(annotationSet != null){ - return ComputeIterator.of(annotationSet.iterator(), annotationItem -> - DexAnnotation.create(DexClass.this, annotationItem)); - } - return EmptyIterator.of(); - } - @Override - public Iterator getAnnotations(TypeKey typeKey){ - AnnotationSet annotationSet = getId().getClassAnnotations(); - if(annotationSet != null){ - return ComputeIterator.of(annotationSet.getAll(typeKey), annotationItem -> - DexAnnotation.create(DexClass.this, annotationItem)); - } - return EmptyIterator.of(); - } - @Override - public DexAnnotation getAnnotation(TypeKey typeKey){ - AnnotationSet annotationSet = getId().getClassAnnotations(); - if(annotationSet != null){ - return DexAnnotation.create(this, annotationSet.get(typeKey)); - } - return null; - } - @Override - public DexAnnotation getOrCreateAnnotation(TypeKey typeKey){ - return DexAnnotation.create(this, - getId().getOrCreateClassAnnotations().getOrCreate(typeKey)); - } - @Override - public DexAnnotation getOrCreateAnnotation(AnnotationItemKey annotationItemKey){ - return DexAnnotation.create(this, - getId().getOrCreateClassAnnotations().getOrCreate(annotationItemKey)); - } - @Override - public DexAnnotation newAnnotation(TypeKey typeKey){ - return DexAnnotation.create(this, - getId().getOrCreateClassAnnotations().addNewItem(typeKey)); - } - ClassData getOrCreateClassData(){ return getId().getOrCreateClassData(); } @@ -693,11 +631,6 @@ public String toSmali(SmaliWriter writer) throws IOException { return SmaliWriter.toString(writer,this); } - @Override - public ElementType getElementType(){ - return ElementType.TYPE; - } - @Override public int hashCode() { return getKey().hashCode(); diff --git a/src/main/java/com/reandroid/dex/model/DexDeclaration.java b/src/main/java/com/reandroid/dex/model/DexDeclaration.java index c0a005886..e7de62f03 100644 --- a/src/main/java/com/reandroid/dex/model/DexDeclaration.java +++ b/src/main/java/com/reandroid/dex/model/DexDeclaration.java @@ -19,8 +19,11 @@ import com.reandroid.dex.common.IdDefinition; import com.reandroid.dex.common.Modifier; import com.reandroid.dex.id.IdItem; +import com.reandroid.dex.key.AnnotationItemKey; +import com.reandroid.dex.key.AnnotationSetKey; import com.reandroid.dex.key.Key; import com.reandroid.dex.key.TypeKey; +import com.reandroid.utils.collection.ComputeIterator; import java.util.Iterator; @@ -148,32 +151,44 @@ public boolean isInSameFile(DexDeclaration dexDeclaration){ return true; } DexLayout dexLayout = getDexLayout(); - if(dexLayout == null){ + if (dexLayout == null) { return false; } return dexLayout == dexDeclaration.getDexLayout(); } - public boolean isInSameFile(DexLayout dexLayout){ - return dexLayout != null && - dexLayout.getDexLayoutBlock() == getDexLayout().getDexLayoutBlock(); - } - public boolean isInSameDirectory(DexDeclaration dexDeclaration){ - if(dexDeclaration == null){ - return false; - } - if(isInSameFile(dexDeclaration)){ - return true; - } - DexDirectory directory = getDexDirectory(); - if(directory == null){ - return false; - } - return directory == dexDeclaration.getDexDirectory(); - } public boolean isInSameDirectory(DexDirectory directory){ return getDexDirectory() == directory; } + @Override + public Iterator getAnnotations() { + AnnotationSetKey annotation = getDefinition().getAnnotation(); + return ComputeIterator.of(annotation.iterator(), this::initializeAnnotation); + } + @Override + public DexAnnotation getAnnotation(TypeKey typeKey) { + return initializeAnnotation(typeKey); + } + @Override + public DexAnnotation getOrCreateAnnotation(TypeKey typeKey) { + IdDefinition definition = getDefinition(); + AnnotationSetKey annotationSetKey = definition.getAnnotation(); + if (!annotationSetKey.contains(typeKey)) { + annotationSetKey = annotationSetKey.getOrCreate(typeKey); + definition.setAnnotation(annotationSetKey); + } + return initializeAnnotation(typeKey); + } + + DexAnnotation initializeAnnotation(TypeKey typeKey) { + return DexAnnotation.create(this, getDefinition(), typeKey); + } + DexAnnotation initializeAnnotation(AnnotationItemKey key) { + if (key != null) { + return DexAnnotation.create(this, getDefinition(), key.getType()); + } + return null; + } @Override public int hashCode() { diff --git a/src/main/java/com/reandroid/dex/model/DexField.java b/src/main/java/com/reandroid/dex/model/DexField.java index 84e6f7d4f..ae54838d7 100644 --- a/src/main/java/com/reandroid/dex/model/DexField.java +++ b/src/main/java/com/reandroid/dex/model/DexField.java @@ -21,13 +21,8 @@ import com.reandroid.dex.ins.Opcode; import com.reandroid.dex.key.*; import com.reandroid.dex.smali.SmaliWriter; -import com.reandroid.utils.collection.CollectionUtil; -import com.reandroid.utils.collection.ComputeIterator; -import com.reandroid.utils.collection.ExpandIterator; -import com.reandroid.utils.collection.FilterIterator; import java.io.IOException; -import java.lang.annotation.ElementType; import java.util.Iterator; public class DexField extends DexDeclaration { @@ -129,35 +124,6 @@ public FieldDef getDefinition() { return fieldDef; } - @Override - public Iterator getAnnotations(){ - return ComputeIterator.of(ExpandIterator.of(getDefinition().getAnnotationSets()), - annotationItem -> DexAnnotation.create(DexField.this, annotationItem)); - } - @Override - public Iterator getAnnotations(TypeKey typeKey){ - return FilterIterator.of(getAnnotations(), - item -> typeKey.equals(item.getType())); - } - @Override - public DexAnnotation getAnnotation(TypeKey typeKey){ - return CollectionUtil.getFirst(getAnnotations(typeKey)); - } - @Override - public DexAnnotation getOrCreateAnnotation(TypeKey typeKey){ - return DexAnnotation.create(this, - getDefinition().getOrCreateAnnotationSet().getOrCreate(typeKey)); - } - @Override - public DexAnnotation getOrCreateAnnotation(AnnotationItemKey annotationItemKey){ - return DexAnnotation.create(this, - getDefinition().getOrCreateAnnotationSet().getOrCreate(annotationItemKey)); - } - @Override - public DexAnnotation newAnnotation(TypeKey typeKey){ - return DexAnnotation.create(this, - getDefinition().getOrCreateAnnotationSet().addNewItem(typeKey)); - } @Override public void removeSelf(){ getDefinition().removeSelf(); @@ -168,11 +134,6 @@ public void append(SmaliWriter writer) throws IOException { getDefinition().append(writer); } - @Override - public ElementType getElementType(){ - return ElementType.FIELD; - } - @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/src/main/java/com/reandroid/dex/model/DexMethod.java b/src/main/java/com/reandroid/dex/model/DexMethod.java index 422db2c11..45d9f7a4f 100644 --- a/src/main/java/com/reandroid/dex/model/DexMethod.java +++ b/src/main/java/com/reandroid/dex/model/DexMethod.java @@ -23,17 +23,13 @@ import com.reandroid.dex.ins.Ins; import com.reandroid.dex.ins.Opcode; import com.reandroid.dex.ins.TryBlock; -import com.reandroid.dex.key.AnnotationItemKey; -import com.reandroid.dex.key.Key; -import com.reandroid.dex.key.MethodKey; -import com.reandroid.dex.key.TypeKey; +import com.reandroid.dex.key.*; import com.reandroid.dex.smali.SmaliReader; import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.dex.smali.model.SmaliInstruction; import com.reandroid.utils.collection.*; import java.io.IOException; -import java.lang.annotation.ElementType; import java.util.Iterator; import java.util.List; import java.util.function.Predicate; @@ -126,35 +122,6 @@ public void setName(String name){ getDefinition().setName(name); } - @Override - public Iterator getAnnotations(){ - return ComputeIterator.of(ExpandIterator.of(getDefinition().getAnnotationSets()), - annotationItem -> DexAnnotation.create(DexMethod.this, annotationItem)); - } - @Override - public Iterator getAnnotations(TypeKey typeKey){ - return FilterIterator.of(getAnnotations(), - item -> typeKey.equals(item.getType())); - } - @Override - public DexAnnotation getAnnotation(TypeKey typeKey){ - return CollectionUtil.getFirst(getAnnotations(typeKey)); - } - @Override - public DexAnnotation getOrCreateAnnotation(TypeKey typeKey){ - return DexAnnotation.create(this, - getDefinition().getOrCreateAnnotationSet().getOrCreate(typeKey)); - } - @Override - public DexAnnotation getOrCreateAnnotation(AnnotationItemKey annotationItemKey){ - return DexAnnotation.create(this, - getDefinition().getOrCreateAnnotationSet().getOrCreate(annotationItemKey)); - } - @Override - public DexAnnotation newAnnotation(TypeKey typeKey){ - return DexAnnotation.create(this, - getDefinition().getOrCreateAnnotationSet().addNewItem(typeKey)); - } public Iterator getInstructions(Opcode opcode) { return getInstructions(ins -> ins.getOpcode() == opcode); } @@ -323,6 +290,9 @@ public Iterator getParameters(){ return ComputeIterator.of(getDefinition().getParameters(), parameter -> DexMethodParameter.create(DexMethod.this, parameter)); } + public void removeParameter(int index) { + getDefinition().removeParameter(index); + } @Override public void removeSelf(){ @@ -332,10 +302,7 @@ public void removeSelf(){ public void append(SmaliWriter writer) throws IOException { getDefinition().append(writer); } - @Override - public ElementType getElementType(){ - return ElementType.METHOD; - } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/src/main/java/com/reandroid/dex/model/DexMethodParameter.java b/src/main/java/com/reandroid/dex/model/DexMethodParameter.java index cb5352673..939377bde 100644 --- a/src/main/java/com/reandroid/dex/model/DexMethodParameter.java +++ b/src/main/java/com/reandroid/dex/model/DexMethodParameter.java @@ -15,61 +15,29 @@ */ package com.reandroid.dex.model; +import com.reandroid.dex.common.IdDefinition; import com.reandroid.dex.data.MethodParameter; import com.reandroid.dex.key.AnnotationItemKey; +import com.reandroid.dex.key.AnnotationSetKey; import com.reandroid.dex.key.Key; import com.reandroid.dex.key.TypeKey; import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.utils.ObjectsUtil; -import com.reandroid.utils.collection.CollectionUtil; import com.reandroid.utils.collection.ComputeIterator; -import com.reandroid.utils.collection.FilterIterator; import java.io.IOException; -import java.lang.annotation.ElementType; import java.util.Iterator; -public class DexMethodParameter extends Dex implements AnnotatedDex{ +public class DexMethodParameter extends Dex implements AnnotatedDex { private final DexMethod dexMethod; private final MethodParameter parameter; - public DexMethodParameter(DexMethod dexMethod, MethodParameter parameter){ + public DexMethodParameter(DexMethod dexMethod, MethodParameter parameter) { this.dexMethod = dexMethod; this.parameter = parameter; } - @Override - public Iterator getAnnotations(){ - return ComputeIterator.of(getParameter().getAnnotationItemBlocks(), - annotationItem -> DexAnnotation.create( - DexMethodParameter.this, annotationItem)); - } - @Override - public Iterator getAnnotations(TypeKey typeKey){ - return FilterIterator.of(getAnnotations(), - dexAnnotation -> typeKey.equals(dexAnnotation.getType())); - } - @Override - public DexAnnotation getAnnotation(TypeKey typeKey){ - return CollectionUtil.getFirst(getAnnotations(typeKey)); - } - @Override - public DexAnnotation getOrCreateAnnotation(TypeKey typeKey){ - return DexAnnotation.create(this, - getParameter().getOrCreateAnnotationItemBlock(typeKey)); - } - @Override - public DexAnnotation getOrCreateAnnotation(AnnotationItemKey annotationItemKey){ - return DexAnnotation.create(this, - getParameter().getOrCreateAnnotationSet().getOrCreate(annotationItemKey)); - } - @Override - public DexAnnotation newAnnotation(TypeKey typeKey){ - return DexAnnotation.create(this, - getParameter().addAnnotationItemBlock(typeKey)); - } - public String getDebugName(){ return getParameter().getDebugName(); } @@ -120,16 +88,42 @@ public DexClassRepository getClassRepository() { @Override public void removeSelf() { - getParameter().onRemoved(); + getDexMethod().removeParameter(getIndex()); } @Override - public void append(SmaliWriter writer) throws IOException { - getParameter().append(writer); + public Iterator getAnnotations() { + AnnotationSetKey annotation = getParameter().getAnnotation(); + return ComputeIterator.of(annotation.iterator(), this::initializeAnnotation); + } + @Override + public DexAnnotation getAnnotation(TypeKey typeKey) { + return initializeAnnotation(typeKey); + } + @Override + public DexAnnotation getOrCreateAnnotation(TypeKey typeKey) { + MethodParameter parameter = getParameter(); + AnnotationSetKey annotationSetKey = parameter.getAnnotation(); + if (!annotationSetKey.contains(typeKey)) { + annotationSetKey = annotationSetKey.getOrCreate(typeKey); + parameter.setAnnotation(annotationSetKey); + } + return initializeAnnotation(typeKey); + } + + private DexAnnotation initializeAnnotation(TypeKey typeKey) { + return DexAnnotation.create(this, getParameter(), typeKey); + } + DexAnnotation initializeAnnotation(AnnotationItemKey key) { + if (key != null) { + return DexAnnotation.create(this, getParameter(), key.getType()); + } + return null; } + @Override - public ElementType getElementType(){ - return ElementType.PARAMETER; + public void append(SmaliWriter writer) throws IOException { + getParameter().append(writer); } public static DexMethodParameter create(DexMethod dexMethod, MethodParameter parameter){ diff --git a/src/main/java/com/reandroid/dex/model/RClassParent.java b/src/main/java/com/reandroid/dex/model/RClassParent.java index c62b7603e..40f275cfb 100644 --- a/src/main/java/com/reandroid/dex/model/RClassParent.java +++ b/src/main/java/com/reandroid/dex/model/RClassParent.java @@ -24,16 +24,14 @@ import com.reandroid.dex.ins.Ins35c; import com.reandroid.dex.ins.Opcode; import com.reandroid.dex.data.*; +import com.reandroid.dex.key.ArrayValueKey; +import com.reandroid.dex.key.Key; import com.reandroid.dex.key.MethodKey; import com.reandroid.dex.key.TypeKey; -import com.reandroid.dex.value.ArrayValue; -import com.reandroid.dex.value.DexValueBlock; -import com.reandroid.dex.value.DexValueType; -import com.reandroid.dex.value.TypeValue; import com.reandroid.utils.CompareUtil; import com.reandroid.utils.collection.ArrayCollection; +import com.reandroid.utils.collection.CollectionUtil; import com.reandroid.utils.collection.ComputeIterator; -import com.reandroid.utils.collection.FilterIterator; import com.reandroid.utils.io.IOUtil; import org.xmlpull.v1.XmlSerializer; @@ -90,55 +88,32 @@ public RClass getOrCreateMember(String simpleName){ return rClass; } public void addMemberAnnotation(String simpleName){ - ArrayValue arrayValue = getOrCreateMembersArray(); - Iterator iterator = FilterIterator.of(getMemberSimpleNames(), simpleName::equals); - if(iterator.hasNext()){ + if(CollectionUtil.contains(getMemberSimpleNames(), simpleName)) { return; } - TypeValue typeValue = arrayValue.createNext(DexValueType.TYPE); - typeValue.setKey(getKey().createInnerClass(simpleName)); - } - public Iterator getMemberSimpleNames(){ - return ComputeIterator.of(getMemberNames(), DexUtils::getSimpleInnerName); - } - public Iterator getMemberNames(){ - ArrayValue arrayValue = getOrCreateMembersArray(); - return ComputeIterator.of(arrayValue.iterator(TypeValue.class), typeValue -> getKey().getTypeName()); - } - private ArrayValue getOrCreateMembersArray(){ - AnnotationItem item = getOrCreateMemberAnnotation(); - AnnotationElement element = item.getElement("value"); - DexValueBlock value = element.getValueBlock(); - if(value == null){ - ArrayValue array = DexValueType.ARRAY.newInstance(); - element.setValue(array); - value = array; - } - return (ArrayValue) value; - } - private AnnotationItem getOrCreateMemberAnnotation(){ - AnnotationSet annotationSet = getOrCreateClassAnnotations(); - String name = "value"; - AnnotationItem item = annotationSet.getOrCreate(TypeKey.DALVIK_MemberClass, name); - AnnotationElement element = item.getElement(name); - if(element.getValueType() == DexValueType.ARRAY){ - return item; - } - item.setVisibility(AnnotationVisibility.SYSTEM); - ArrayValue array = DexValueType.ARRAY.newInstance(); - element.setValue(array); - return item; - } - private AnnotationSet getOrCreateClassAnnotations() { - AnnotationSet annotationSet = getClassAnnotations(); - if(annotationSet != null){ - return annotationSet; + ArrayValueKey arrayValue = getOrCreateMembersArray() + .add(getKey().createInnerClass(simpleName)); + DexAnnotation annotation = getOrCreateAnnotation(TypeKey.DALVIK_MemberClass); + DexAnnotationElement element = annotation.getOrCreate(Key.DALVIK_value); + element.setValue(arrayValue); + } + public Iterator getMemberSimpleNames() { + return ComputeIterator.of(getMemberNames(), TypeKey::getSimpleInnerName); + } + public Iterator getMemberNames(){ + return getOrCreateMembersArray().iterator(TypeKey.class); + } + private ArrayValueKey getOrCreateMembersArray() { + DexAnnotation annotation = getOrCreateAnnotation(TypeKey.DALVIK_MemberClass); + annotation.setVisibility(AnnotationVisibility.SYSTEM); + DexAnnotationElement element = annotation.getOrCreate(Key.DALVIK_value); + Key key = element.getValue(); + if (key instanceof ArrayValueKey) { + return (ArrayValueKey) key; } - annotationSet = getId().getOrCreateClassAnnotations(); - return annotationSet; - } - private AnnotationSet getClassAnnotations() { - return getId().getClassAnnotations(); + ArrayValueKey arrayValueKey = ArrayValueKey.EMPTY; + element.setValue(arrayValueKey); + return arrayValueKey; } public void initialize(){ ClassId classId = getId(); diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliAnnotationElement.java b/src/main/java/com/reandroid/dex/smali/model/SmaliAnnotationElement.java index 254c0f020..bd04b0b09 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliAnnotationElement.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliAnnotationElement.java @@ -35,7 +35,7 @@ public SmaliAnnotationElement(){ @Override public AnnotationElementKey getKey() { - return new AnnotationElementKey(getName(), getValueKey()); + return AnnotationElementKey.create(getName(), getValueKey()); } @Override public void setKey(Key key) { diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliAnnotationItem.java b/src/main/java/com/reandroid/dex/smali/model/SmaliAnnotationItem.java index a43a6fcff..019e2a63f 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliAnnotationItem.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliAnnotationItem.java @@ -47,7 +47,7 @@ public AnnotationItemKey getKey() { for (int i = 0; i < length; i++) { elements[i] = get(i).getKey(); } - return new AnnotationItemKey(getVisibility(), getType(), elements); + return AnnotationItemKey.create(getVisibility(), getType(), elements); } @Override public void setKey(Key key) {