From f7f01e3bc5c1eea5b7fd98d6269de59e82e32475 Mon Sep 17 00:00:00 2001 From: REAndroid Date: Mon, 2 Dec 2024 20:37:49 +0100 Subject: [PATCH] [DEX] Abstracting smali and dex classes with similar structure --- .../com/reandroid/dex/common/AccessFlag.java | 26 ++++ .../reandroid/dex/common/IdDefinition.java | 22 +-- .../com/reandroid/dex/common/Modifier.java | 7 + .../dex/dalvik/DalvikAnnotation.java | 61 ++++++++ .../reandroid/dex/dalvik/DalvikEnclosing.java | 61 ++++++++ .../dex/dalvik/DalvikEnclosingClass.java | 47 ++++++ .../dex/dalvik/DalvikEnclosingMethod.java | 45 ++++++ .../dex/dalvik/DalvikInnerClass.java | 76 ++++++++++ .../dex/dalvik/DalvikMemberClass.java | 106 +++++++++++++ .../reandroid/dex/dalvik/DalvikSignature.java | 80 ++++++++++ .../reandroid/dex/dalvik/DalvikThrows.java | 65 ++++++++ src/main/java/com/reandroid/dex/data/Def.java | 31 +--- .../java/com/reandroid/dex/data/DefIndex.java | 4 +- .../java/com/reandroid/dex/data/FieldDef.java | 49 +++--- .../com/reandroid/dex/data/MethodDef.java | 41 ++---- .../reandroid/dex/data/MethodParameter.java | 14 +- .../java/com/reandroid/dex/id/ClassId.java | 139 +++++++----------- .../reandroid/dex/key/AnnotationSetKey.java | 4 + .../java/com/reandroid/dex/key/ArrayKey.java | 5 + .../com/reandroid/dex/key/ArrayValueKey.java | 5 + .../java/com/reandroid/dex/key/FieldKey.java | 7 +- .../java/com/reandroid/dex/key/KeyList.java | 39 ++++- .../java/com/reandroid/dex/key/MethodKey.java | 8 +- .../com/reandroid/dex/key/ProgramKey.java | 23 +++ .../java/com/reandroid/dex/key/TypeKey.java | 10 +- .../com/reandroid/dex/key/TypeListKey.java | 10 ++ .../reandroid/dex/model/AccessibleDex.java | 32 ++++ .../com/reandroid/dex/model/AnnotatedDex.java | 65 ++++++-- .../com/reandroid/dex/model/DalvikUtil.java | 34 +---- .../reandroid/dex/model/DexAnnotation.java | 24 +-- .../com/reandroid/dex/model/DexClass.java | 89 +++++------ .../reandroid/dex/model/DexDeclaration.java | 68 +-------- .../com/reandroid/dex/model/DexField.java | 19 ++- .../com/reandroid/dex/model/DexMethod.java | 15 +- .../dex/model/DexMethodParameter.java | 56 ++----- .../java/com/reandroid/dex/model/RClass.java | 40 ++++- .../com/reandroid/dex/model/RClassParent.java | 35 +---- .../dex/program/AccessibleProgram.java | 73 +++++++++ .../AnnotatedProgram.java} | 4 +- .../reandroid/dex/program/ClassProgram.java | 43 ++++++ .../reandroid/dex/program/FieldProgram.java | 36 +++++ .../dex/program/MethodParameterProgram.java | 29 ++++ .../reandroid/dex/program/MethodProgram.java | 44 ++++++ .../reandroid/dex/program/ProgramElement.java | 25 ++++ .../dex/reference/TypeListReference.java | 11 ++ .../java/com/reandroid/dex/resource/R.java | 23 +-- .../dex/sections/DexLayoutBlock.java | 6 +- .../reandroid/dex/smali/model/SmaliClass.java | 46 ++++-- .../reandroid/dex/smali/model/SmaliDef.java | 104 ++++++------- .../reandroid/dex/smali/model/SmaliField.java | 30 ++-- .../dex/smali/model/SmaliInterfaceSet.java | 2 +- .../dex/smali/model/SmaliMethod.java | 16 +- .../dex/smali/model/SmaliMethodParameter.java | 83 ++++++++--- .../graph/InlineFieldIntResolver.java | 2 +- 54 files changed, 1435 insertions(+), 604 deletions(-) create mode 100644 src/main/java/com/reandroid/dex/dalvik/DalvikAnnotation.java create mode 100644 src/main/java/com/reandroid/dex/dalvik/DalvikEnclosing.java create mode 100644 src/main/java/com/reandroid/dex/dalvik/DalvikEnclosingClass.java create mode 100644 src/main/java/com/reandroid/dex/dalvik/DalvikEnclosingMethod.java create mode 100644 src/main/java/com/reandroid/dex/dalvik/DalvikInnerClass.java create mode 100644 src/main/java/com/reandroid/dex/dalvik/DalvikMemberClass.java create mode 100644 src/main/java/com/reandroid/dex/dalvik/DalvikSignature.java create mode 100644 src/main/java/com/reandroid/dex/dalvik/DalvikThrows.java create mode 100644 src/main/java/com/reandroid/dex/key/ProgramKey.java create mode 100644 src/main/java/com/reandroid/dex/model/AccessibleDex.java create mode 100644 src/main/java/com/reandroid/dex/program/AccessibleProgram.java rename src/main/java/com/reandroid/dex/{common/AnnotatedItem.java => program/AnnotatedProgram.java} (96%) create mode 100644 src/main/java/com/reandroid/dex/program/ClassProgram.java create mode 100644 src/main/java/com/reandroid/dex/program/FieldProgram.java create mode 100644 src/main/java/com/reandroid/dex/program/MethodParameterProgram.java create mode 100644 src/main/java/com/reandroid/dex/program/MethodProgram.java create mode 100644 src/main/java/com/reandroid/dex/program/ProgramElement.java diff --git a/src/main/java/com/reandroid/dex/common/AccessFlag.java b/src/main/java/com/reandroid/dex/common/AccessFlag.java index 8ee433bd7..99b681a73 100644 --- a/src/main/java/com/reandroid/dex/common/AccessFlag.java +++ b/src/main/java/com/reandroid/dex/common/AccessFlag.java @@ -18,7 +18,9 @@ import com.reandroid.dex.smali.SmaliReader; import com.reandroid.utils.collection.ArrayCollection; import com.reandroid.utils.collection.ArrayIterator; +import com.reandroid.utils.collection.EmptyIterator; +import java.lang.annotation.ElementType; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -117,6 +119,18 @@ private AccessFlag(int value, String name, boolean validForClass, boolean validF public boolean isSet(int accessFlags) { return (getValue() & accessFlags) != 0; } + public boolean isSet(ElementType elementType, int accessFlags) { + if (elementType == ElementType.TYPE) { + return isSetForClass(accessFlags); + } + if (elementType == ElementType.FIELD) { + return isSetForField(accessFlags); + } + if (elementType == ElementType.METHOD) { + return isSetForMethod(accessFlags); + } + return false; + } private boolean isSetForField(int value) { return validForField && (getValue() & value) != 0; } @@ -127,6 +141,18 @@ private boolean isSetForClass(int value) { return validForClass && (getValue() & value) != 0; } + public static Iterator valuesOf(ElementType elementType, int value) { + if (elementType == ElementType.TYPE) { + return valuesOfClass(value); + } + if (elementType == ElementType.FIELD) { + return valuesOfField(value); + } + if (elementType == ElementType.METHOD) { + return valuesOfMethod(value); + } + return EmptyIterator.of(); + } public static Iterator valuesOfClass(int value) { return getValues(accessFlag -> accessFlag.isSetForClass(value)); } diff --git a/src/main/java/com/reandroid/dex/common/IdDefinition.java b/src/main/java/com/reandroid/dex/common/IdDefinition.java index f4f340fd6..b96047cf4 100644 --- a/src/main/java/com/reandroid/dex/common/IdDefinition.java +++ b/src/main/java/com/reandroid/dex/common/IdDefinition.java @@ -17,26 +17,10 @@ package com.reandroid.dex.common; import com.reandroid.dex.id.IdItem; +import com.reandroid.dex.program.AccessibleProgram; -import java.util.Iterator; +public interface IdDefinition extends AccessibleProgram { -public interface IdDefinition extends AnnotatedItem { T getId(); - int getAccessFlagsValue(); - Iterator getAccessFlags(); - default Iterator getModifiers(){ - return getAccessFlags(); - } - void setAccessFlagsValue(int value); - default void addAccessFlag(AccessFlag flag) { - int current = getAccessFlagsValue(); - int value = flag.getValue(); - if((value & 0x7) != 0){ - current = current & ~0x7; - } - setAccessFlagsValue(current | value); - } - default void removeAccessFlag(AccessFlag flag) { - setAccessFlagsValue(getAccessFlagsValue() & ~flag.getValue()); - } + } diff --git a/src/main/java/com/reandroid/dex/common/Modifier.java b/src/main/java/com/reandroid/dex/common/Modifier.java index 2bacacd49..29a02ffa4 100644 --- a/src/main/java/com/reandroid/dex/common/Modifier.java +++ b/src/main/java/com/reandroid/dex/common/Modifier.java @@ -125,4 +125,11 @@ public static int combineValues(Modifier[] modifiers){ } return result; } + public static int combineValues(Iterator iterator) { + int result = 0; + while (iterator.hasNext()) { + result += iterator.next().getValue(); + } + return result; + } } diff --git a/src/main/java/com/reandroid/dex/dalvik/DalvikAnnotation.java b/src/main/java/com/reandroid/dex/dalvik/DalvikAnnotation.java new file mode 100644 index 000000000..e70d2eb6d --- /dev/null +++ b/src/main/java/com/reandroid/dex/dalvik/DalvikAnnotation.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.dalvik; + +import com.reandroid.dex.program.ProgramElement; +import com.reandroid.dex.key.AnnotationItemKey; +import com.reandroid.dex.key.Key; +import com.reandroid.dex.key.TypeKey; + +public class DalvikAnnotation { + + private final ProgramElement programElement; + private final TypeKey annotationType; + + protected DalvikAnnotation(ProgramElement programElement, TypeKey annotationType) { + this.programElement = programElement; + this.annotationType = annotationType; + } + + public AnnotationItemKey getKey() { + return getProgramElement().getAnnotation(getAnnotationType()); + } + public void setKey(AnnotationItemKey key) { + if (!getAnnotationType().equals(key.getType())) { + throw new IllegalArgumentException("Different annotation type: " + + getAnnotationType() + ", " + key.getType()); + } + getProgramElement().addAnnotation(key); + } + public TypeKey getAnnotationType() { + return annotationType; + } + public ProgramElement getProgramElement() { + return programElement; + } + + Key readValue(String name) { + return getKey().getValue(name); + } + void writeValue(String name, Key value) { + setKey(getKey().add(name, value)); + } + + @Override + public String toString() { + return getKey().toString(); + } +} diff --git a/src/main/java/com/reandroid/dex/dalvik/DalvikEnclosing.java b/src/main/java/com/reandroid/dex/dalvik/DalvikEnclosing.java new file mode 100644 index 000000000..dd2c5e004 --- /dev/null +++ b/src/main/java/com/reandroid/dex/dalvik/DalvikEnclosing.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.dalvik; + +import com.reandroid.dex.key.Key; +import com.reandroid.dex.key.NullValueKey; +import com.reandroid.dex.key.TypeKey; +import com.reandroid.dex.program.ProgramElement; +import com.reandroid.utils.ObjectsUtil; + +public abstract class DalvikEnclosing extends DalvikAnnotation { + + public DalvikEnclosing(ProgramElement programElement, TypeKey annotationType) { + super(programElement, annotationType); + } + + public T getEnclosing() { + Key value = readValue(Key.DALVIK_value); + if (value == null || (value instanceof NullValueKey)) { + return null; + } + return ObjectsUtil.cast(value); + } + public void setEnclosing(T enclosing) { + Key value = enclosing == null ? NullValueKey.INSTANCE : enclosing; + writeValue(Key.DALVIK_value, value); + } + public TypeKey getEnclosingClass() { + Key key = getEnclosing(); + if (key != null) { + return key.getDeclaring(); + } + return null; + } + + @Override + public String toString() { + return String.valueOf(getEnclosing()); + } + + public static DalvikEnclosing of(ProgramElement programElement) { + DalvikEnclosing enclosing = DalvikEnclosingClass.of(programElement); + if (enclosing == null) { + enclosing = DalvikEnclosingMethod.of(programElement); + } + return enclosing; + } +} diff --git a/src/main/java/com/reandroid/dex/dalvik/DalvikEnclosingClass.java b/src/main/java/com/reandroid/dex/dalvik/DalvikEnclosingClass.java new file mode 100644 index 000000000..bb3ec108c --- /dev/null +++ b/src/main/java/com/reandroid/dex/dalvik/DalvikEnclosingClass.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.dalvik; + +import com.reandroid.dex.common.AnnotationVisibility; +import com.reandroid.dex.key.*; +import com.reandroid.dex.program.ProgramElement; + +public class DalvikEnclosingClass extends DalvikEnclosing { + + private DalvikEnclosingClass(ProgramElement programElement) { + super(programElement, TypeKey.DALVIK_EnclosingClass); + } + + public static DalvikEnclosingClass of(ProgramElement programElement) { + if (programElement.hasAnnotation(TypeKey.DALVIK_EnclosingClass)) { + return new DalvikEnclosingClass(programElement); + } + return null; + } + public static DalvikEnclosingClass getOrCreate(ProgramElement programElement) { + if (!programElement.hasAnnotation(TypeKey.DALVIK_EnclosingClass)) { + TypeKey typeKey = (TypeKey) programElement.getKey(); + typeKey = typeKey.getEnclosingClass(); + programElement.addAnnotation(AnnotationItemKey.create( + AnnotationVisibility.SYSTEM, + TypeKey.DALVIK_EnclosingClass, + AnnotationElementKey.create(Key.DALVIK_value, typeKey) + ) + ); + } + return of(programElement); + } +} diff --git a/src/main/java/com/reandroid/dex/dalvik/DalvikEnclosingMethod.java b/src/main/java/com/reandroid/dex/dalvik/DalvikEnclosingMethod.java new file mode 100644 index 000000000..564feb8f2 --- /dev/null +++ b/src/main/java/com/reandroid/dex/dalvik/DalvikEnclosingMethod.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.dalvik; + +import com.reandroid.dex.common.AnnotationVisibility; +import com.reandroid.dex.key.*; +import com.reandroid.dex.program.ProgramElement; + +public class DalvikEnclosingMethod extends DalvikEnclosing { + + private DalvikEnclosingMethod(ProgramElement programElement) { + super(programElement, TypeKey.DALVIK_EnclosingMethod); + } + + public static DalvikEnclosingMethod of(ProgramElement programElement) { + if (programElement.hasAnnotation(TypeKey.DALVIK_EnclosingMethod)) { + return new DalvikEnclosingMethod(programElement); + } + return null; + } + public static DalvikEnclosingMethod getOrCreate(ProgramElement programElement) { + if (!programElement.hasAnnotation(TypeKey.DALVIK_EnclosingMethod)) { + programElement.addAnnotation(AnnotationItemKey.create( + AnnotationVisibility.SYSTEM, + TypeKey.DALVIK_EnclosingMethod, + AnnotationElementKey.create(Key.DALVIK_value, NullValueKey.INSTANCE) + ) + ); + } + return of(programElement); + } +} diff --git a/src/main/java/com/reandroid/dex/dalvik/DalvikInnerClass.java b/src/main/java/com/reandroid/dex/dalvik/DalvikInnerClass.java new file mode 100644 index 000000000..2a644c69b --- /dev/null +++ b/src/main/java/com/reandroid/dex/dalvik/DalvikInnerClass.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.dalvik; + +import com.reandroid.dex.common.AccessFlag; +import com.reandroid.dex.common.AnnotationVisibility; +import com.reandroid.dex.key.*; +import com.reandroid.dex.program.ProgramElement; + +import java.util.Iterator; + +public class DalvikInnerClass extends DalvikAnnotation { + + private DalvikInnerClass(ProgramElement programElement) { + super(programElement, TypeKey.DALVIK_InnerClass); + } + + public Iterator getAccessFlags() { + return AccessFlag.valuesOfClass(getAccessFlagsValue()); + } + public int getAccessFlagsValue() { + PrimitiveKey key = (PrimitiveKey) readValue(Key.DALVIK_accessFlags); + return (int) key.getValueAsLong(); + } + public void setAccessFlags(int flags) { + writeValue(Key.DALVIK_accessFlags, PrimitiveKey.of(flags)); + } + public String getName() { + Key key = getKey().getValue(Key.DALVIK_name); + if (key instanceof StringKey) { + return ((StringKey) key).getString(); + } + return null; + } + public void setName(String name) { + Key key = name == null? NullValueKey.INSTANCE : StringKey.create(name); + writeValue(Key.DALVIK_name, key); + } + + @Override + public String toString() { + return AccessFlag.toString(getAccessFlags()) + getName(); + } + + public static DalvikInnerClass of(ProgramElement programElement) { + if (programElement.hasAnnotation(TypeKey.DALVIK_InnerClass)) { + return new DalvikInnerClass(programElement); + } + return null; + } + public static DalvikInnerClass getOrCreate(ProgramElement programElement) { + if (!programElement.hasAnnotation(TypeKey.DALVIK_InnerClass)) { + programElement.addAnnotation(AnnotationItemKey.create( + AnnotationVisibility.SYSTEM, + TypeKey.DALVIK_InnerClass, + AnnotationElementKey.create(Key.DALVIK_accessFlags, PrimitiveKey.of(0)), + AnnotationElementKey.create(Key.DALVIK_name, NullValueKey.INSTANCE) + ) + ); + } + return of(programElement); + } +} diff --git a/src/main/java/com/reandroid/dex/dalvik/DalvikMemberClass.java b/src/main/java/com/reandroid/dex/dalvik/DalvikMemberClass.java new file mode 100644 index 000000000..aeb551b14 --- /dev/null +++ b/src/main/java/com/reandroid/dex/dalvik/DalvikMemberClass.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.dalvik; + +import com.reandroid.dex.common.AnnotationVisibility; +import com.reandroid.dex.key.*; +import com.reandroid.dex.program.ClassProgram; +import com.reandroid.dex.program.ProgramElement; +import com.reandroid.utils.CompareUtil; +import com.reandroid.utils.ObjectsUtil; +import com.reandroid.utils.StringsUtil; + +import java.util.Iterator; +import java.util.function.Predicate; + +public class DalvikMemberClass extends DalvikAnnotation { + + private DalvikMemberClass(ProgramElement programElement) { + super(programElement, TypeKey.DALVIK_MemberClass); + } + + public Iterator getMembers() { + return getArray().iterator(TypeKey.class); + } + public int size() { + return getArray().size(); + } + public void add(TypeKey typeKey) { + ArrayValueKey array = getArray() + .remove(typeKey) + .add(typeKey) + .sort(CompareUtil.getComparableComparator()); + setArray(array); + } + public void remove(TypeKey typeKey) { + ArrayValueKey array = getArray() + .remove(typeKey) + .add(typeKey); + setArray(array); + } + public void removeIf(Predicate predicate) { + ArrayValueKey array = getArray() + .removeIf(ObjectsUtil.cast(predicate)); + setArray(array); + } + public boolean contains(TypeKey typeKey) { + return getArray().contains(typeKey); + } + public boolean isEmpty() { + return getArray().isEmpty(); + } + public void addSimpleName(String simpleName) { + TypeKey typeKey = ((ClassProgram) getProgramElement()).getKey(); + typeKey = typeKey.createInnerClass(simpleName); + add(typeKey); + } + public ArrayValueKey getArray() { + ArrayValueKey arrayValueKey = (ArrayValueKey) readValue(Key.DALVIK_value); + if (arrayValueKey == null) { + arrayValueKey = ArrayValueKey.EMPTY; + } + return arrayValueKey; + } + public void setArray(ArrayValueKey array) { + if (array == null) { + array = ArrayValueKey.EMPTY; + } + writeValue(Key.DALVIK_value, array); + } + + @Override + public String toString() { + return StringsUtil.join(getMembers(), "\n"); + } + + public static DalvikMemberClass of(ProgramElement programElement) { + if (programElement.hasAnnotation(TypeKey.DALVIK_MemberClass)) { + return new DalvikMemberClass(programElement); + } + return null; + } + public static DalvikMemberClass getOrCreate(ProgramElement programElement) { + if (!programElement.hasAnnotation(TypeKey.DALVIK_MemberClass)) { + programElement.addAnnotation(AnnotationItemKey.create( + AnnotationVisibility.SYSTEM, + TypeKey.DALVIK_MemberClass, + AnnotationElementKey.create(Key.DALVIK_value, ArrayValueKey.EMPTY) + ) + ); + } + return of(programElement); + } +} diff --git a/src/main/java/com/reandroid/dex/dalvik/DalvikSignature.java b/src/main/java/com/reandroid/dex/dalvik/DalvikSignature.java new file mode 100644 index 000000000..dc6770525 --- /dev/null +++ b/src/main/java/com/reandroid/dex/dalvik/DalvikSignature.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.dalvik; + +import com.reandroid.dex.common.AnnotationVisibility; +import com.reandroid.dex.key.*; +import com.reandroid.dex.program.ProgramElement; + +public class DalvikSignature extends DalvikAnnotation { + + private DalvikSignature(ProgramElement programElement) { + super(programElement, TypeKey.DALVIK_Signature); + } + + public String[] values() { + String[] values = getArrayKey().getStringValues(); + if (values == null) { + values = new String[0]; + } + return values; + } + public void values(String[] values) { + setArrayKey(ArrayValueKey.of(values)); + } + public ArrayValueKey getArrayKey() { + ArrayValueKey key = (ArrayValueKey) getKey().getValue(Key.DALVIK_value); + if (key == null) { + key = ArrayValueKey.EMPTY; + } + return key; + } + public void setArrayKey(ArrayValueKey arrayKey) { + setKey(getKey().add(Key.DALVIK_value, arrayKey)); + } + + public String getString() { + String[] values = values(); + StringBuilder builder = new StringBuilder(); + for (String value : values) { + builder.append(value); + } + return builder.toString(); + } + + @Override + public String toString() { + return getString(); + } + + public static DalvikSignature of(ProgramElement programElement) { + if (programElement.hasAnnotation(TypeKey.DALVIK_Signature)) { + return new DalvikSignature(programElement); + } + return null; + } + public static DalvikSignature getOrCreate(ProgramElement programElement) { + if (!programElement.hasAnnotation(TypeKey.DALVIK_Signature)) { + programElement.addAnnotation(AnnotationItemKey.create( + AnnotationVisibility.SYSTEM, + TypeKey.DALVIK_Signature, + AnnotationElementKey.create(Key.DALVIK_value, ArrayValueKey.EMPTY) + ) + ); + } + return of(programElement); + } +} diff --git a/src/main/java/com/reandroid/dex/dalvik/DalvikThrows.java b/src/main/java/com/reandroid/dex/dalvik/DalvikThrows.java new file mode 100644 index 000000000..ef005c989 --- /dev/null +++ b/src/main/java/com/reandroid/dex/dalvik/DalvikThrows.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.dalvik; + +import com.reandroid.dex.common.AnnotationVisibility; +import com.reandroid.dex.key.*; +import com.reandroid.dex.program.MethodProgram; + +public class DalvikThrows extends DalvikAnnotation { + + private DalvikThrows(MethodProgram methodProgram) { + super(methodProgram, TypeKey.DALVIK_Throws); + } + public TypeKey getThrow() { + Key key = readValue(Key.DALVIK_value); + if (key == null || (key instanceof NullValueKey)) { + return null; + } + return (TypeKey) key; + } + public void setThrow(TypeKey typeKey) { + writeValue(Key.DALVIK_value, typeKey); + } + + @Override + public MethodProgram getProgramElement() { + return (MethodProgram) super.getProgramElement(); + } + + @Override + public String toString() { + return String.valueOf(getThrow()); + } + + public static DalvikThrows of(MethodProgram methodProgram) { + if (methodProgram.hasAnnotation(TypeKey.DALVIK_MemberClass)) { + return new DalvikThrows(methodProgram); + } + return null; + } + public static DalvikThrows getOrCreate(MethodProgram methodProgram) { + if (!methodProgram.hasAnnotation(TypeKey.DALVIK_Throws)) { + methodProgram.addAnnotation(AnnotationItemKey.create( + AnnotationVisibility.SYSTEM, + TypeKey.DALVIK_Throws, + AnnotationElementKey.create(Key.DALVIK_value, TypeKey.EXCEPTION) + ) + ); + } + return of(methodProgram); + } +} diff --git a/src/main/java/com/reandroid/dex/data/Def.java b/src/main/java/com/reandroid/dex/data/Def.java index 58d5b9095..c265db7cb 100644 --- a/src/main/java/com/reandroid/dex/data/Def.java +++ b/src/main/java/com/reandroid/dex/data/Def.java @@ -21,10 +21,7 @@ import com.reandroid.dex.common.*; import com.reandroid.dex.id.ClassId; 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.dex.key.*; import com.reandroid.dex.pool.DexSectionPool; import com.reandroid.dex.sections.Section; import com.reandroid.dex.sections.SectionList; @@ -39,7 +36,7 @@ import java.util.Iterator; public abstract class Def extends FixedDexContainerWithTool implements - IdDefinition, EditableItem, Comparable>, AnnotatedItem, SmaliRegion, + IdDefinition, EditableItem, Comparable>, SmaliRegion, DefIndex, IdUsageIterator { private final SectionType sectionType; @@ -170,13 +167,8 @@ void onRemove(){ relativeId.set(0); } @Override - public Key getKey(){ - T item = getId(); - if(item != null){ - return item.getKey(); - } - return null; - } + public abstract ProgramKey getKey(); + public void setKey(Key key){ setItem(key); } @@ -269,21 +261,6 @@ public int getAccessFlagsValue() { public void setAccessFlagsValue(int value) { accessFlags.set(value); } - public boolean isPrivate(){ - return AccessFlag.PRIVATE.isSet(getAccessFlagsValue()); - } - public boolean isNative(){ - return AccessFlag.NATIVE.isSet(getAccessFlagsValue()); - } - public boolean isStatic(){ - return AccessFlag.STATIC.isSet(getAccessFlagsValue()); - } - public boolean isFinal(){ - return AccessFlag.FINAL.isSet(getAccessFlagsValue()); - } - public boolean isConstructor(){ - return AccessFlag.CONSTRUCTOR.isSet(getAccessFlagsValue()); - } public boolean isDirect(){ return false; } diff --git a/src/main/java/com/reandroid/dex/data/DefIndex.java b/src/main/java/com/reandroid/dex/data/DefIndex.java index eee1a10aa..5a56ef96a 100644 --- a/src/main/java/com/reandroid/dex/data/DefIndex.java +++ b/src/main/java/com/reandroid/dex/data/DefIndex.java @@ -15,9 +15,9 @@ */ package com.reandroid.dex.data; -import com.reandroid.dex.key.Key; +import com.reandroid.dex.key.ProgramKey; public interface DefIndex { int getDefinitionIndex(); - Key getKey(); + ProgramKey getKey(); } diff --git a/src/main/java/com/reandroid/dex/data/FieldDef.java b/src/main/java/com/reandroid/dex/data/FieldDef.java index a9a14e90d..215a64676 100644 --- a/src/main/java/com/reandroid/dex/data/FieldDef.java +++ b/src/main/java/com/reandroid/dex/data/FieldDef.java @@ -21,18 +21,18 @@ import com.reandroid.dex.id.FieldId; import com.reandroid.dex.id.IdItem; import com.reandroid.dex.key.*; +import com.reandroid.dex.program.FieldProgram; import com.reandroid.dex.sections.SectionType; import com.reandroid.dex.smali.SmaliDirective; import com.reandroid.dex.smali.model.Smali; import com.reandroid.dex.smali.model.SmaliField; -import com.reandroid.dex.smali.model.SmaliValue; import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.utils.collection.SingleIterator; import java.io.IOException; import java.util.Iterator; -public class FieldDef extends Def { +public class FieldDef extends Def implements FieldProgram { private Key cachedStaticValue; @@ -42,9 +42,14 @@ public FieldDef() { @Override public FieldKey getKey() { - return (FieldKey) super.getKey(); + FieldId id = getId(); + if (id != null) { + return id.getKey(); + } + return null; } + @Override public Key getStaticValue() { StaticFieldDefArray fieldDefArray = getParentInstance( StaticFieldDefArray.class); @@ -71,11 +76,6 @@ void cachedStaticValue(Key staticValue) { this.cachedStaticValue = staticValue; } - @Override - public Iterator getAccessFlags(){ - return AccessFlag.valuesOfField(getAccessFlagsValue()); - } - @Override public void append(SmaliWriter writer) throws IOException { writer.newLine(); @@ -152,7 +152,7 @@ public void validateStaticValue() { throw new DexException("Mismatch in type object vs primitive for value: " + SmaliWriter.toStringSafe(staticValue) + ", in field: " + fieldKey + "\n"); } - if (typeKey.isPrimitive()) { + if (staticValue instanceof PrimitiveKey) { TypeKey valueType = ((PrimitiveKey) staticValue).valueType(); if (!typeKey.equals(valueType)) { throw new DexException("Mismatch in type: " + typeKey @@ -160,6 +160,10 @@ public void validateStaticValue() { + ", for value: " + SmaliWriter.toStringSafe(staticValue) + ", in field: " + fieldKey); } + } else if (typeKey.isPrimitive()) { + throw new DexException("Mismatch in type: " + typeKey + + " vs L " + ", for value: " + + SmaliWriter.toStringSafe(staticValue) + ", in field: " + fieldKey); } } @Override @@ -183,9 +187,9 @@ public void fromSmali(Smali smali) { if(smaliField.hasAnnotation()){ setAnnotation(smaliField.getAnnotationSetKey()); } - SmaliValue smaliValue = smaliField.getValue(); - if(smaliValue != null) { - setStaticValue(smaliValue.getKey()); + Key value = smaliField.getStaticValue(); + if(value != null) { + setStaticValue(value); } } @@ -194,7 +198,7 @@ public SmaliField toSmali() { SmaliField smaliField = new SmaliField(); smaliField.setKey(getKey()); smaliField.setAccessFlags(AccessFlag.valuesOfField(getAccessFlagsValue())); - smaliField.setValue(getStaticValue()); + smaliField.setStaticValue(getStaticValue()); smaliField.setAnnotation(getAnnotationKeys()); return smaliField; } @@ -203,23 +207,4 @@ public SmaliField toSmali() { public String toString() { return SmaliWriter.toStringSafe(this); } - public String toString1() { - FieldId fieldId = getId(); - if (fieldId != null) { - StringBuilder builder = new StringBuilder(); - builder.append(getSmaliDirective()); - builder.append(" "); - builder.append(Modifier.toString(getModifiers())); - builder.append(" "); - builder.append(fieldId); - Key staticValue = getStaticValue(); - if (staticValue != null) { - builder.append(" = "); - builder.append(staticValue); - } - return builder.toString(); - } - return getSmaliDirective() + " " + Modifier.toString(getModifiers()) - + " " + getRelativeIdValue(); - } } diff --git a/src/main/java/com/reandroid/dex/data/MethodDef.java b/src/main/java/com/reandroid/dex/data/MethodDef.java index 1906f4c6b..0d070075b 100644 --- a/src/main/java/com/reandroid/dex/data/MethodDef.java +++ b/src/main/java/com/reandroid/dex/data/MethodDef.java @@ -25,6 +25,7 @@ import com.reandroid.dex.ins.Ins; import com.reandroid.dex.ins.TryBlock; import com.reandroid.dex.key.*; +import com.reandroid.dex.program.MethodProgram; import com.reandroid.dex.reference.DataItemUle128Reference; import com.reandroid.dex.sections.SectionType; import com.reandroid.dex.smali.SmaliDirective; @@ -35,10 +36,11 @@ import com.reandroid.utils.collection.*; import java.io.IOException; +import java.lang.annotation.ElementType; import java.util.Iterator; import java.util.Objects; -public class MethodDef extends Def{ +public class MethodDef extends Def implements MethodProgram { private final DataItemUle128Reference codeOffset; @@ -47,14 +49,12 @@ public MethodDef() { this.codeOffset = new DataItemUle128Reference<>(SectionType.CODE, UsageMarker.USAGE_DEFINITION); addChild(2, codeOffset); } - public boolean isBridge(){ - return AccessFlag.BRIDGE.isSet(getAccessFlagsValue()); - } @Override - public boolean isDirect(){ - return isConstructor() || isPrivate() || isStatic(); + public ElementType getElementType() { + return ElementType.METHOD; } + public String getName() { MethodId methodId = getId(); if(methodId != null) { @@ -117,7 +117,11 @@ public int getCount() { } @Override public MethodKey getKey(){ - return (MethodKey) super.getKey(); + MethodId id = getId(); + if (id != null) { + return id.getKey(); + } + return null; } @Override @@ -125,7 +129,7 @@ void onRemove() { CodeItem codeItem = codeOffset.getItem(); if(codeItem != null){ codeItem.setMethodDef(null); - this.codeOffset.setItem((CodeItem) null); + this.codeOffset.setItem(null); } super.onRemove(); } @@ -246,7 +250,7 @@ public CodeItem getCodeItem(){ return codeItem; } public void clearCode(){ - codeOffset.setItem((CodeItem) null); + codeOffset.setItem(null); } public void clearDebug(){ CodeItem codeItem = getCodeItem(); @@ -262,25 +266,6 @@ private void linkCodeItem(){ } } - public Iterator getParameterAnnotations(){ - AnnotationsDirectory directory = getAnnotationsDirectory(); - if(directory != null){ - return directory.getParameterAnnotation(this); - } - return EmptyIterator.of(); - } - public Iterator getParameterAnnotations(int parameterIndex){ - AnnotationsDirectory directory = getAnnotationsDirectory(); - if(directory == null){ - return EmptyIterator.of(); - } - return directory.getParameterAnnotation(getDefinitionIndex(), parameterIndex); - } - @Override - public Iterator getAccessFlags(){ - return AccessFlag.valuesOfMethod(getAccessFlagsValue()); - } - @Override public void onReadBytes(BlockReader reader) throws IOException { super.onReadBytes(reader); diff --git a/src/main/java/com/reandroid/dex/data/MethodParameter.java b/src/main/java/com/reandroid/dex/data/MethodParameter.java index 0c2f60c8c..ec45e1c59 100644 --- a/src/main/java/com/reandroid/dex/data/MethodParameter.java +++ b/src/main/java/com/reandroid/dex/data/MethodParameter.java @@ -15,13 +15,12 @@ */ package com.reandroid.dex.data; -import com.reandroid.dex.common.AnnotatedItem; import com.reandroid.dex.debug.DebugParameter; import com.reandroid.dex.id.ProtoId; import com.reandroid.dex.id.TypeId; import com.reandroid.dex.key.AnnotationSetKey; -import com.reandroid.dex.key.Key; import com.reandroid.dex.key.TypeKey; +import com.reandroid.dex.program.MethodParameterProgram; import com.reandroid.dex.smali.SmaliDirective; import com.reandroid.dex.smali.SmaliRegion; import com.reandroid.dex.smali.SmaliWriter; @@ -34,7 +33,7 @@ import java.io.IOException; import java.util.Iterator; -public class MethodParameter implements DefIndex, AnnotatedItem, SmaliRegion { +public class MethodParameter implements DefIndex, MethodParameterProgram, SmaliRegion { private final MethodDef methodDef; private final int index; @@ -142,6 +141,7 @@ public void clearDebugParameter() { } } + @Override public String getDebugName() { DebugParameter debugParameter = getDebugParameter(); if (debugParameter != null) { @@ -149,7 +149,7 @@ public String getDebugName() { } return null; } - + @Override public void setDebugName(String name) { if (StringsUtil.isEmpty(name)) { name = null; @@ -180,7 +180,7 @@ public DebugParameter getDebugParameter() { } @Override - public Key getKey() { + public TypeKey getKey() { TypeId typeId = getTypeId(); if (typeId != null) { return typeId.getKey(); @@ -190,9 +190,9 @@ public Key getKey() { public void fromSmali(SmaliMethodParameter smaliMethodParameter) { if (smaliMethodParameter.hasAnnotations()) { - setAnnotation(smaliMethodParameter.getAnnotationSet().getKey()); + setAnnotation(smaliMethodParameter.getSmaliAnnotationSet().getKey()); } - setDebugName(smaliMethodParameter.getName()); + setDebugName(smaliMethodParameter.getDebugName()); } public boolean isEmpty() { diff --git a/src/main/java/com/reandroid/dex/id/ClassId.java b/src/main/java/com/reandroid/dex/id/ClassId.java index ce091108f..f59128a94 100644 --- a/src/main/java/com/reandroid/dex/id/ClassId.java +++ b/src/main/java/com/reandroid/dex/id/ClassId.java @@ -19,22 +19,24 @@ import com.reandroid.arsc.item.IndirectInteger; import com.reandroid.dex.base.UsageMarker; import com.reandroid.dex.common.*; +import com.reandroid.dex.dalvik.DalvikEnclosing; +import com.reandroid.dex.dalvik.DalvikMemberClass; import com.reandroid.dex.data.*; import com.reandroid.dex.key.*; +import com.reandroid.dex.program.ClassProgram; import com.reandroid.dex.reference.DataItemIndirectReference; import com.reandroid.dex.reference.TypeListReference; import com.reandroid.dex.sections.Section; import com.reandroid.dex.sections.SectionType; import com.reandroid.dex.smali.model.SmaliClass; import com.reandroid.dex.smali.SmaliWriter; -import com.reandroid.utils.StringsUtil; import com.reandroid.utils.collection.*; import java.io.IOException; import java.util.Iterator; import java.util.Objects; -public class ClassId extends IdItem implements IdDefinition, Comparable { +public class ClassId extends IdItem implements ClassProgram, IdDefinition, Comparable { private final ClassTypeId classTypeId; private final IndirectInteger accessFlagValue; @@ -150,10 +152,6 @@ public int getAccessFlagsValue() { return accessFlagValue.get(); } @Override - public Iterator getAccessFlags(){ - return AccessFlag.valuesOfClass(getAccessFlagsValue()); - } - @Override public void setAccessFlagsValue(int value) { accessFlagValue.set(value); } @@ -163,33 +161,37 @@ public void setId(TypeId typeId){ public SuperClassId getSuperClassId(){ return superClassId; } - public TypeId getSuperClassType(){ + public TypeId getSuperClassType() { return getSuperClassId().getItem(); } + @Override public TypeKey getSuperClassKey(){ return getSuperClassId().getKey(); } public void setSuperClass(TypeKey typeKey){ this.superClassId.setKey(typeKey); } - public void setSuperClass(String superClass){ - this.superClassId.setKey(new TypeKey(superClass)); - } - public SourceFile getSourceFile(){ + public SourceFile getSourceFileReference(){ return sourceFile; } - public String getSourceFileName(){ - return getSourceFile().getString(); + @Override + public String getSourceFileName() { + return getSourceFileReference().getString(); } public void setSourceFile(String sourceFile){ - getSourceFile().setString(sourceFile); + getSourceFileReference().setString(sourceFile); } public Iterator getInstanceKeys(){ - return CombiningIterator.singleOne(getSuperClassKey(), getInterfaceKeys()); + return CombiningIterator.singleOne(getSuperClassKey(), getInterfacesKey().iterator()); } - public Iterator getInterfaceKeys(){ - return getInterfacesReference().getTypeKeys(); + @Override + public TypeListKey getInterfacesKey() { + TypeListKey typeListKey = interfaces.getKey(); + if (typeListKey == null) { + typeListKey = TypeListKey.EMPTY; + } + return typeListKey; } public TypeList getInterfaceTypeList(){ return interfaces.getItem(); @@ -201,80 +203,53 @@ public void setInterfaces(TypeListKey typeListKey){ this.interfaces.setKey(typeListKey); } - public Key getDalvikEnclosing(){ - TypeKey typeKey = getDalvikEnclosingClass(); - if(typeKey != null) { - return typeKey; - } - MethodKey enclosingMethod = getDalvikEnclosingMethod(); - if (enclosingMethod != null) { - return enclosingMethod.getDeclaring(); + @Override + public Iterator getStaticFields() { + ClassData classData = getClassData(); + if (classData != null) { + return classData.getStaticFields(); } - return null; + return EmptyIterator.of(); } - public Iterator getDalvikMemberClasses() { - Key key = getAnnotationValue(TypeKey.DALVIK_MemberClass, Key.DALVIK_value); - if (key instanceof KeyList) { - return ((KeyList) key).iterator(TypeKey.class); + @Override + public Iterator getInstanceFields() { + ClassData classData = getClassData(); + if (classData != null) { + return classData.getInstanceFields(); } return EmptyIterator.of(); } - public MethodKey getDalvikEnclosingMethod() { - Key key = getAnnotationValue(TypeKey.DALVIK_EnclosingMethod, Key.DALVIK_value); - if (key instanceof MethodKey) { - return (MethodKey) key; + + @Override + public Iterator getDirectMethods() { + ClassData classData = getClassData(); + if (classData != null) { + return classData.getDirectMethods(); } - return null; + return EmptyIterator.of(); } - public AnnotationItemKey getOrCreateDalvikInnerClass(){ - TypeKey typeKey = getKey(); - if (typeKey == null) { - return null; - } - String inner = typeKey.getSimpleInnerName(); - if(AccessFlag.SYNTHETIC.isSet(getAccessFlagsValue()) - || inner.equals(typeKey.getSimpleName()) - || StringsUtil.isDigits(inner)){ - inner = null; - } - return getOrCreateDalvikInnerClass(getAccessFlagsValue(), inner); - } - 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 TypeKey getOrCreateDalvikEnclosingClass(){ - TypeKey key = getKey(); - if(key != null){ - TypeKey enclosing = key.getEnclosingClass(); - if(!key.equals(enclosing)){ - return getOrCreateDalvikEnclosingClass(enclosing); - } + @Override + public Iterator getVirtualMethods() { + ClassData classData = getClassData(); + if (classData != null) { + return classData.getVirtualMethods(); } - return null; + return EmptyIterator.of(); } - public TypeKey getOrCreateDalvikEnclosingClass(TypeKey enclosing) { - if (enclosing == null) { - return null; + + public TypeKey getDalvikEnclosing() { + DalvikEnclosing enclosing = DalvikEnclosing.of(this); + if (enclosing != null) { + return enclosing.getEnclosingClass(); } - AnnotationItemKey itemKey = AnnotationItemKey.create(AnnotationVisibility.SYSTEM, - TypeKey.DALVIK_EnclosingClass) - .add(Key.DALVIK_value, enclosing); - AnnotationSetKey annotation = getAnnotation().add(itemKey); - setAnnotation(annotation); - return enclosing; + return null; } - public TypeKey getDalvikEnclosingClass() { - Key key = getAnnotationValue(TypeKey.DALVIK_EnclosingClass, Key.DALVIK_value); - if (key instanceof TypeKey) { - return (TypeKey) key; + public Iterator getDalvikMemberClasses() { + DalvikMemberClass dalvikMemberClass = DalvikMemberClass.of(this); + if (dalvikMemberClass != null) { + return dalvikMemberClass.getMembers(); } - return null; + return EmptyIterator.of(); } public AnnotationsDirectory getUniqueAnnotationsDirectory(){ return annotationsDirectory.getUniqueItem(this); @@ -450,7 +425,7 @@ public void fromSmali(SmaliClass smaliClass) throws IOException { setKey(smaliClass.getKey()); setAccessFlagsValue(smaliClass.getAccessFlagsValue()); - setSuperClass(smaliClass.getSuperClass()); + setSuperClass(smaliClass.getSuperClassKey()); setSourceFile(smaliClass.getSourceFileName()); setInterfaces(smaliClass.getInterfacesKey()); @@ -466,7 +441,7 @@ public SmaliClass toSmali() { smaliClass.setKey(getKey()); smaliClass.setAccessFlags(InstanceIterator.of(getAccessFlags(), AccessFlag.class)); smaliClass.setSuperClass(getSuperClassKey()); - smaliClass.setSourceFile(getSourceFile().getKey()); + smaliClass.setSourceFile(getSourceFileReference().getKey()); smaliClass.setInterfaces(getInterfacesReference().getKey()); smaliClass.setAnnotation(getAnnotation()); ClassData classData = getClassData(); @@ -480,7 +455,7 @@ public SmaliClass toSmali() { public void append(SmaliWriter writer) throws IOException { getClassTypeId().append(writer); getSuperClassId().append(writer); - getSourceFile().append(writer); + getSourceFileReference().append(writer); writer.newLine(); TypeList interfaces = getInterfaceTypeList(); if(interfaces != null){ diff --git a/src/main/java/com/reandroid/dex/key/AnnotationSetKey.java b/src/main/java/com/reandroid/dex/key/AnnotationSetKey.java index b462e89f0..decf7962b 100644 --- a/src/main/java/com/reandroid/dex/key/AnnotationSetKey.java +++ b/src/main/java/com/reandroid/dex/key/AnnotationSetKey.java @@ -21,6 +21,7 @@ import com.reandroid.utils.ObjectsUtil; import com.reandroid.utils.collection.ArrayCollection; import com.reandroid.utils.collection.ArraySort; +import com.reandroid.utils.collection.ComputeIterator; import java.io.IOException; import java.util.Iterator; @@ -41,6 +42,9 @@ private AnnotationSetKey(AnnotationItemKey[] elements) { super(elements); } + public Iterator getTypes() { + return ComputeIterator.of(iterator(), AnnotationItemKey::getType); + } public AnnotationSetKey removeElementIf(TypeKey typeKey, Predicate predicate) { AnnotationSetKey result = this; AnnotationItemKey itemKey = result.get(typeKey); diff --git a/src/main/java/com/reandroid/dex/key/ArrayKey.java b/src/main/java/com/reandroid/dex/key/ArrayKey.java index 82790ce7d..8d1735879 100644 --- a/src/main/java/com/reandroid/dex/key/ArrayKey.java +++ b/src/main/java/com/reandroid/dex/key/ArrayKey.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.io.StringWriter; +import java.util.Comparator; import java.util.function.Predicate; public class ArrayKey extends KeyList { @@ -63,6 +64,10 @@ public ArrayKey removeIf(Predicate predicate) { public ArrayKey set(int i, Key item) { return (ArrayKey) super.set(i, item); } + @Override + public ArrayKey sort(Comparator comparator) { + return (ArrayKey) super.sort(comparator); + } @Override ArrayKey newInstance(Key[] elements) { diff --git a/src/main/java/com/reandroid/dex/key/ArrayValueKey.java b/src/main/java/com/reandroid/dex/key/ArrayValueKey.java index 6b7b8af5e..d3d9e217c 100644 --- a/src/main/java/com/reandroid/dex/key/ArrayValueKey.java +++ b/src/main/java/com/reandroid/dex/key/ArrayValueKey.java @@ -20,6 +20,7 @@ import com.reandroid.dex.smali.SmaliWriter; import java.io.IOException; +import java.util.Comparator; import java.util.function.Predicate; public class ArrayValueKey extends ArrayKey { @@ -120,6 +121,10 @@ public ArrayValueKey removeIf(Predicate predicate) { public ArrayValueKey set(int i, Key item) { return (ArrayValueKey) super.set(i, item); } + @Override + public ArrayValueKey sort(Comparator comparator) { + return (ArrayValueKey) super.sort(comparator); + } @Override ArrayValueKey newInstance(Key[] elements) { diff --git a/src/main/java/com/reandroid/dex/key/FieldKey.java b/src/main/java/com/reandroid/dex/key/FieldKey.java index 724dc2d59..75a3448e0 100644 --- a/src/main/java/com/reandroid/dex/key/FieldKey.java +++ b/src/main/java/com/reandroid/dex/key/FieldKey.java @@ -24,10 +24,11 @@ import com.reandroid.utils.collection.SingleIterator; import java.io.IOException; +import java.lang.annotation.ElementType; import java.lang.reflect.Field; import java.util.Iterator; -public class FieldKey implements Key { +public class FieldKey implements ProgramKey { private final TypeKey declaring; private final StringKey name; @@ -39,6 +40,10 @@ public class FieldKey implements Key { this.type = type; } + @Override + public ElementType getElementType() { + return ElementType.FIELD; + } @Override public TypeKey getDeclaring() { return declaring; diff --git a/src/main/java/com/reandroid/dex/key/KeyList.java b/src/main/java/com/reandroid/dex/key/KeyList.java index ad516dcf3..0fabd9e45 100644 --- a/src/main/java/com/reandroid/dex/key/KeyList.java +++ b/src/main/java/com/reandroid/dex/key/KeyList.java @@ -18,12 +18,10 @@ import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.utils.CompareUtil; 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 com.reandroid.utils.collection.*; import java.io.IOException; +import java.util.Comparator; import java.util.Iterator; import java.util.function.Predicate; @@ -68,6 +66,16 @@ public int indexOf(Object key) { } return -1; } + public boolean contains(Object item) { + T[] elements = this.elements; + int length = elements.length; + for (int i = 0; i < length; i++) { + if (ObjectsUtil.equals(elements[i], item)) { + return true; + } + } + return false; + } public KeyList set(int i, T item) { if (ObjectsUtil.equals(item, get(i))) { return this; @@ -165,6 +173,29 @@ public KeyList sorted() { } return newInstance(elements); } + public KeyList sort(Comparator comparator) { + T[] elements = this.elements; + int length = elements.length; + if (length < 2) { + return this; + } + boolean sortRequired = false; + T previous = elements[0]; + for (int i = 1; i < length; i++) { + T item = elements[i]; + if (comparator.compare(previous, item) > 0) { + sortRequired = true; + break; + } + previous = item; + } + if (!sortRequired) { + return this; + } + elements = elements.clone(); + ArraySort.sort(elements, comparator); + return newInstance(elements); + } private T[] getSortedElements() { T[] elements = this.sortedElements; if (elements == null) { diff --git a/src/main/java/com/reandroid/dex/key/MethodKey.java b/src/main/java/com/reandroid/dex/key/MethodKey.java index d56abd0e2..c5554a282 100644 --- a/src/main/java/com/reandroid/dex/key/MethodKey.java +++ b/src/main/java/com/reandroid/dex/key/MethodKey.java @@ -25,12 +25,13 @@ import com.reandroid.utils.collection.SingleIterator; import java.io.IOException; +import java.lang.annotation.ElementType; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.Iterator; import java.util.function.Function; -public class MethodKey implements Key { +public class MethodKey implements ProgramKey { private final TypeKey declaring; private final StringKey nameKey; @@ -45,6 +46,11 @@ public MethodKey(TypeKey declaring, String name, ProtoKey proto){ this(declaring, StringKey.create(name), proto); } + @Override + public ElementType getElementType() { + return ElementType.METHOD; + } + public int getRegister(int index) { return getProto().getRegister(index); } diff --git a/src/main/java/com/reandroid/dex/key/ProgramKey.java b/src/main/java/com/reandroid/dex/key/ProgramKey.java new file mode 100644 index 000000000..32c8e2775 --- /dev/null +++ b/src/main/java/com/reandroid/dex/key/ProgramKey.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.key; + +import java.lang.annotation.ElementType; + +public interface ProgramKey extends Key { + TypeKey getDeclaring(); + ElementType getElementType(); +} diff --git a/src/main/java/com/reandroid/dex/key/TypeKey.java b/src/main/java/com/reandroid/dex/key/TypeKey.java index deb1e9723..6df8cedaf 100644 --- a/src/main/java/com/reandroid/dex/key/TypeKey.java +++ b/src/main/java/com/reandroid/dex/key/TypeKey.java @@ -26,9 +26,10 @@ import com.reandroid.utils.collection.SingleIterator; import java.io.IOException; +import java.lang.annotation.ElementType; import java.util.Iterator; -public class TypeKey implements Key{ +public class TypeKey implements ProgramKey { private final String typeName; private String simpleName; @@ -37,6 +38,11 @@ public TypeKey(String typeName) { this.typeName = typeName; } + @Override + public ElementType getElementType() { + return ElementType.TYPE; + } + public String getTypeName() { return typeName; } @@ -583,10 +589,12 @@ public boolean isWide() { public static final TypeKey CLASS = new TypeKey("Ljava/lang/Class;"); public static final TypeKey OBJECT = new TypeKey("Ljava/lang/Object;"); public static final TypeKey STRING = new TypeKey("Ljava/lang/String;"); + public static final TypeKey EXCEPTION = new TypeKey("Ljava/lang/Exception;"); public static final TypeKey DALVIK_EnclosingClass = new TypeKey("Ldalvik/annotation/EnclosingClass;"); public static final TypeKey DALVIK_EnclosingMethod = new TypeKey("Ldalvik/annotation/EnclosingMethod;"); public static final TypeKey DALVIK_InnerClass = new TypeKey("Ldalvik/annotation/InnerClass;"); public static final TypeKey DALVIK_MemberClass = new TypeKey("Ldalvik/annotation/MemberClasses;"); public static final TypeKey DALVIK_Signature = new TypeKey("Ldalvik/annotation/Signature;"); + public static final TypeKey DALVIK_Throws = new TypeKey("Ldalvik/annotation/Throws;"); } diff --git a/src/main/java/com/reandroid/dex/key/TypeListKey.java b/src/main/java/com/reandroid/dex/key/TypeListKey.java index ad9eb8679..24ea6decf 100644 --- a/src/main/java/com/reandroid/dex/key/TypeListKey.java +++ b/src/main/java/com/reandroid/dex/key/TypeListKey.java @@ -17,6 +17,7 @@ import com.reandroid.dex.smali.SmaliParseException; import com.reandroid.dex.smali.SmaliReader; +import com.reandroid.utils.ObjectsUtil; import com.reandroid.utils.StringsUtil; import com.reandroid.utils.collection.ArrayCollection; @@ -74,6 +75,15 @@ public TypeListKey remove(TypeKey itemKey) { public TypeListKey set(int i, TypeKey item) { return (TypeListKey) super.set(i, item); } + public boolean contains(TypeKey typeKey) { + int size = size(); + for (int i = 0; i < size; i++) { + if (ObjectsUtil.equals(typeKey, get(i))) { + return true; + } + } + return false; + } @Override public TypeListKey replaceKey(Key search, Key replace) { diff --git a/src/main/java/com/reandroid/dex/model/AccessibleDex.java b/src/main/java/com/reandroid/dex/model/AccessibleDex.java new file mode 100644 index 000000000..1fa9e102e --- /dev/null +++ b/src/main/java/com/reandroid/dex/model/AccessibleDex.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.model; + +import com.reandroid.dex.program.AccessibleProgram; + +public interface AccessibleDex extends AnnotatedDex, AccessibleProgram { + @Override + AccessibleProgram getProgramElement(); + + @Override + default int getAccessFlagsValue() { + return getProgramElement().getAccessFlagsValue(); + } + @Override + default void setAccessFlagsValue(int value) { + getProgramElement().setAccessFlagsValue(value); + } +} diff --git a/src/main/java/com/reandroid/dex/model/AnnotatedDex.java b/src/main/java/com/reandroid/dex/model/AnnotatedDex.java index 3c9367818..10d7da656 100644 --- a/src/main/java/com/reandroid/dex/model/AnnotatedDex.java +++ b/src/main/java/com/reandroid/dex/model/AnnotatedDex.java @@ -15,30 +15,77 @@ */ package com.reandroid.dex.model; +import com.reandroid.dex.key.ProgramKey; +import com.reandroid.dex.program.AnnotatedProgram; +import com.reandroid.dex.key.AnnotationSetKey; import com.reandroid.dex.key.Key; import com.reandroid.dex.key.TypeKey; +import com.reandroid.dex.program.ProgramElement; +import com.reandroid.utils.collection.ComputeIterator; +import java.lang.annotation.ElementType; import java.util.Iterator; -public interface AnnotatedDex { +public interface AnnotatedDex extends ProgramElement { - Iterator getAnnotations(); - DexAnnotation getAnnotation(TypeKey typeKey); - DexAnnotation getOrCreateAnnotation(TypeKey typeKey); + ProgramElement getProgramElement(); - default DexAnnotationElement getAnnotationElement(TypeKey typeKey, String name){ - DexAnnotation dexAnnotation = getAnnotation(typeKey); + @Override + default ProgramKey getKey() { + return getProgramElement().getKey(); + } + @Override + default AnnotationSetKey getAnnotation() { + return getProgramElement().getAnnotation(); + } + @Override + default void setAnnotation(AnnotationSetKey annotationSet) { + getProgramElement().setAnnotation(annotationSet); + } + + @Override + default boolean hasAnnotations() { + return getProgramElement().hasAnnotations(); + } + @Override + default void clearAnnotations() { + getProgramElement().clearAnnotations(); + } + + default Iterator getDexAnnotations() { + AnnotationSetKey annotation = getProgramElement().getAnnotation(); + return ComputeIterator.of(annotation.getTypes(), this::getDexAnnotation); + } + default DexAnnotation getDexAnnotation(TypeKey typeKey) { + AnnotatedProgram annotatedProgram = getProgramElement(); + if (annotatedProgram.hasAnnotation(typeKey)) { + return new DexAnnotation((Dex) this, annotatedProgram, typeKey); + } + return null; + } + default DexAnnotation getOrCreateDexAnnotation(TypeKey typeKey) { + AnnotatedProgram annotatedProgram = getProgramElement(); + AnnotationSetKey annotationSetKey = annotatedProgram.getAnnotation(); + if (!annotationSetKey.contains(typeKey)) { + annotationSetKey = annotationSetKey.getOrCreate(typeKey); + annotatedProgram.setAnnotation(annotationSetKey); + } + return new DexAnnotation((Dex) this, annotatedProgram, typeKey); + } + + default DexAnnotationElement getDexAnnotationElement(TypeKey typeKey, String name){ + DexAnnotation dexAnnotation = getDexAnnotation(typeKey); if(dexAnnotation != null) { return dexAnnotation.get(name); } return null; } - default DexAnnotationElement getOrCreateAnnotationElement(TypeKey typeKey, String name) { - DexAnnotation annotation = getOrCreateAnnotation(typeKey); + default DexAnnotationElement getOrCreateDexAnnotationElement(TypeKey typeKey, String name) { + DexAnnotation annotation = getOrCreateDexAnnotation(typeKey); return annotation.getOrCreate(name); } default Key getAnnotationValue(TypeKey typeKey, String name) { - DexAnnotationElement element = getAnnotationElement(typeKey, name); + DexAnnotationElement element = getDexAnnotationElement(typeKey, name); if (element != null) { return element.getValue(); } diff --git a/src/main/java/com/reandroid/dex/model/DalvikUtil.java b/src/main/java/com/reandroid/dex/model/DalvikUtil.java index 64030e248..e118c9d3c 100644 --- a/src/main/java/com/reandroid/dex/model/DalvikUtil.java +++ b/src/main/java/com/reandroid/dex/model/DalvikUtil.java @@ -15,10 +15,7 @@ */ package com.reandroid.dex.model; -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 com.reandroid.dex.dalvik.DalvikMemberClass; import java.util.Iterator; @@ -34,29 +31,12 @@ public static int cleanMissingMembers(DexClassRepository repository) { } public static int cleanMissingMembers(DexClass dexClass) { int result = 0; - Iterator iterator = SingleIterator.of(dexClass.getAnnotation(TypeKey.DALVIK_MemberClass)); - while (iterator.hasNext()) { - DexAnnotation annotation = iterator.next(); - DexAnnotationElement element = annotation.get("value"); - if(element == null) { - continue; - } - Key value = element.getValue(); - if(value instanceof ArrayKey) { - ArrayKey valueArray = (ArrayKey) value; - DexClassRepository repository = dexClass.getClassRepository(); - ArrayKey changedKey = valueArray.removeIf(key -> !repository.containsClass((TypeKey) key)); - if(changedKey != valueArray) { - result ++; - if(changedKey.isEmpty()) { - element.removeSelf(); - } else { - element.setValue(changedKey); - } - } - } - if(annotation.size() == 0) { - annotation.removeSelf(); + DalvikMemberClass dalvikMemberClass = DalvikMemberClass.of(dexClass); + if (dalvikMemberClass != null) { + DexClassRepository repository = dexClass.getClassRepository(); + dalvikMemberClass.removeIf(typeKey -> !repository.containsClass(typeKey)); + if (dalvikMemberClass.isEmpty()) { + dexClass.removeAnnotation(dalvikMemberClass.getAnnotationType()); } } return result; diff --git a/src/main/java/com/reandroid/dex/model/DexAnnotation.java b/src/main/java/com/reandroid/dex/model/DexAnnotation.java index 30de41818..0648a184e 100644 --- a/src/main/java/com/reandroid/dex/model/DexAnnotation.java +++ b/src/main/java/com/reandroid/dex/model/DexAnnotation.java @@ -16,7 +16,7 @@ package com.reandroid.dex.model; import com.reandroid.common.ArraySupplier; -import com.reandroid.dex.common.AnnotatedItem; +import com.reandroid.dex.program.AnnotatedProgram; import com.reandroid.dex.common.AnnotationVisibility; import com.reandroid.dex.key.*; import com.reandroid.dex.smali.SmaliWriter; @@ -29,14 +29,14 @@ public class DexAnnotation extends Dex implements Iterable{ private final Dex declaring; - private final AnnotatedItem annotatedItem; + private final AnnotatedProgram annotatedProgram; private TypeKey typeKey; private AnnotationItemKey mRemoved; - public DexAnnotation(Dex declaring, AnnotatedItem annotatedItem, TypeKey typeKey){ + public DexAnnotation(Dex declaring, AnnotatedProgram annotatedProgram, TypeKey typeKey){ super(); this.declaring = declaring; - this.annotatedItem = annotatedItem; + this.annotatedProgram = annotatedProgram; this.typeKey = typeKey; } @@ -154,8 +154,8 @@ private void applyRemoveSelf() { public Dex getDeclaring() { return declaring; } - private AnnotatedItem getAnnotatedItem() { - return annotatedItem; + private AnnotatedProgram getAnnotatedItem() { + return annotatedProgram; } private AnnotationSetKey getAnnotationSet() { return getAnnotatedItem().getAnnotation(); @@ -199,16 +199,16 @@ public String toString() { 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); + public static DexAnnotation create(Dex declaring, AnnotatedProgram annotatedProgram, TypeKey typeKey) { + if(declaring != null && annotatedProgram != null && annotatedProgram.hasAnnotation(typeKey)) { + return new DexAnnotation(declaring, annotatedProgram, typeKey); } return null; } - public static DexAnnotation create(Dex declaring, AnnotatedItem annotatedItem, AnnotationItemKey itemKey) { - if(declaring != null && annotatedItem != null && itemKey != null) { - return create(declaring, annotatedItem, itemKey.getType()); + public static DexAnnotation create(Dex declaring, AnnotatedProgram annotatedProgram, AnnotationItemKey itemKey) { + if(declaring != null && annotatedProgram != null && itemKey != null) { + return create(declaring, annotatedProgram, itemKey.getType()); } 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 3bc6137eb..740d877f5 100644 --- a/src/main/java/com/reandroid/dex/model/DexClass.java +++ b/src/main/java/com/reandroid/dex/model/DexClass.java @@ -16,11 +16,12 @@ package com.reandroid.dex.model; import com.reandroid.dex.common.AccessFlag; +import com.reandroid.dex.dalvik.DalvikInnerClass; import com.reandroid.dex.data.*; import com.reandroid.dex.id.ClassId; import com.reandroid.dex.id.IdItem; import com.reandroid.dex.key.*; -import com.reandroid.dex.reference.TypeListReference; +import com.reandroid.dex.program.ClassProgram; import com.reandroid.dex.smali.SmaliReader; import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.dex.smali.model.SmaliField; @@ -34,7 +35,7 @@ import java.util.Set; import java.util.function.Predicate; -public class DexClass extends DexDeclaration implements Comparable { +public class DexClass extends DexDeclaration implements ClassProgram, Comparable { private final DexLayout dexLayout; private final ClassId classId; @@ -285,19 +286,13 @@ public DexField getOrCreateStaticField(FieldKey fieldKey){ public FieldDef getOrCreateStatic(FieldKey fieldKey){ return getOrCreateClassData().getOrCreateStatic(fieldKey); } + @Override public Iterator getStaticFields() { - ClassData classData = getClassData(); - if(classData == null){ - return EmptyIterator.of(); - } - return ComputeIterator.of(classData.getStaticFields(), this::initializeField); + return ComputeIterator.of(getId().getStaticFields(), this::initializeField); } + @Override public Iterator getInstanceFields() { - ClassData classData = getClassData(); - if(classData == null){ - return EmptyIterator.of(); - } - return ComputeIterator.of(classData.getInstanceFields(), this::initializeField); + return ComputeIterator.of(getId().getInstanceFields(), this::initializeField); } public DexField getOrCreateInstanceField(FieldKey fieldKey){ return initializeField(getOrCreateInstance(fieldKey)); @@ -315,19 +310,13 @@ public Iterator getDeclaredMethods(Predicate filter) { public Iterator getDeclaredMethods() { return CombiningIterator.two(getDirectMethods(), getVirtualMethods()); } + @Override public Iterator getDirectMethods() { - ClassData classData = getClassData(); - if(classData == null){ - return EmptyIterator.of(); - } - return ComputeIterator.of(classData.getDirectMethods(), this::initializeMethod); + return ComputeIterator.of(getId().getDirectMethods(), this::initializeMethod); } + @Override public Iterator getVirtualMethods() { - ClassData classData = getClassData(); - if(classData == null){ - return EmptyIterator.of(); - } - return ComputeIterator.of(classData.getVirtualMethods(), this::initializeMethod); + return ComputeIterator.of(getId().getVirtualMethods(), this::initializeMethod); } public DexMethod getOrCreateDirectMethod(MethodKey methodKey){ return initializeMethod(getOrCreateClassData().getOrCreateDirect(methodKey)); @@ -408,6 +397,7 @@ public ClassId getDefinition(){ return getId(); } + @Override public TypeKey getSuperClassKey(){ return getId().getSuperClassKey(); } @@ -422,26 +412,31 @@ public void setSourceFile(String sourceFile){ } public Iterator getInterfaceClasses(){ - return ComputeIterator.of(getInterfaces(), this::search); + return ComputeIterator.of(getInterfacesKey().iterator(), this::search); } DexClass search(TypeKey typeKey){ return getClassRepository().getDexClass(typeKey); } public boolean containsInterface(TypeKey typeKey) { - return CollectionUtil.contains(getInterfaces(), typeKey); + return getInterfacesKey().contains(typeKey); } - public Iterator getInterfaces(){ - return getId().getInterfaceKeys(); + @Override + public TypeListKey getInterfacesKey() { + return getId().getInterfacesKey(); } public void addInterface(TypeKey typeKey) { - getId().getInterfacesReference().add(typeKey); + TypeListKey typeListKey = getInterfacesKey() + .remove(typeKey) + .add(typeKey); + getId().setInterfaces(typeListKey); } public void removeInterface(TypeKey typeKey) { - getId().getInterfacesReference().remove(typeKey); + TypeListKey typeListKey = getInterfacesKey() + .remove(typeKey); + getId().setInterfaces(typeListKey); } public void clearInterfaces() { - TypeListReference reference = getId().getInterfacesReference(); - reference.setItem((TypeList) null); + getId().setInterfaces(TypeListKey.EMPTY); } public void clearDebug(){ Iterator iterator = getDeclaredMethods(); @@ -450,22 +445,15 @@ public void clearDebug(){ } } public void fixDalvikInnerClassName() { - DexAnnotation annotation = getAnnotation(TypeKey.DALVIK_InnerClass); - if (annotation == null) { - return; - } - DexAnnotationElement element = annotation.get(Key.DALVIK_name); - if (element == null) { - return; - } - if (!(element.getValue() instanceof StringKey)) { + DalvikInnerClass dalvikInnerClass = DalvikInnerClass.of(this); + if (dalvikInnerClass == null || dalvikInnerClass.getName() == null) { return; } TypeKey typeKey = getKey(); if (!typeKey.isInnerName()) { - element.setValue(NullValueKey.INSTANCE); + dalvikInnerClass.setName(null); } else { - element.setValue(StringKey.create(typeKey.getSimpleInnerName())); + dalvikInnerClass.setName(typeKey.getSimpleInnerName()); } } public Set fixAccessibility(){ @@ -523,22 +511,21 @@ public TypeKey getDalvikEnclosingClass(){ } return null; } - public String getDalvikInnerClassName(){ - Key key = getAnnotationValue(TypeKey.DALVIK_InnerClass, Key.DALVIK_name); - if(key instanceof StringKey){ - return ((StringKey) key).getString(); + public String getDalvikInnerClassName() { + DalvikInnerClass dalvikInnerClass = DalvikInnerClass.of(this); + if (dalvikInnerClass != null) { + return dalvikInnerClass.getName(); } return null; } public void updateDalvikInnerClassName(String name){ - DexAnnotationElement element = getAnnotationElement(TypeKey.DALVIK_InnerClass, Key.DALVIK_name); - if (element != null) { - element.setValue(StringKey.create(name)); + DalvikInnerClass dalvikInnerClass = DalvikInnerClass.of(this); + if (dalvikInnerClass != null) { + dalvikInnerClass.setName(name); } } - public void createDalvikInnerClassName(String name){ - DexAnnotationElement element = getOrCreateAnnotationElement(TypeKey.DALVIK_InnerClass, Key.DALVIK_name); - element.setValue(StringKey.create(name)); + public void createDalvikInnerClassName(String name) { + DalvikInnerClass.getOrCreate(this).setName(name); } ClassData getOrCreateClassData(){ diff --git a/src/main/java/com/reandroid/dex/model/DexDeclaration.java b/src/main/java/com/reandroid/dex/model/DexDeclaration.java index e7de62f03..9148ca77d 100644 --- a/src/main/java/com/reandroid/dex/model/DexDeclaration.java +++ b/src/main/java/com/reandroid/dex/model/DexDeclaration.java @@ -19,15 +19,14 @@ 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.ProgramKey; import com.reandroid.dex.key.TypeKey; -import com.reandroid.utils.collection.ComputeIterator; +import com.reandroid.dex.program.AccessibleProgram; import java.util.Iterator; -public abstract class DexDeclaration extends Dex implements AnnotatedDex { +public abstract class DexDeclaration extends Dex implements AccessibleDex { public boolean uses(Key key) { if(getKey().equals(key)){ @@ -55,33 +54,6 @@ public boolean isAccessibleTo(DexClass dexClass) { } return myClass == this || isAccessibleTo(defining); } - public boolean isInternal() { - return (getAccessFlagsValue() & 0x7) == 0; - } - public boolean isFinal() { - return AccessFlag.FINAL.isSet(getAccessFlagsValue()); - } - public boolean isPublic() { - return AccessFlag.PUBLIC.isSet(getAccessFlagsValue()); - } - public boolean isProtected() { - return AccessFlag.PROTECTED.isSet(getAccessFlagsValue()); - } - public boolean isPrivate() { - return AccessFlag.PRIVATE.isSet(getAccessFlagsValue()); - } - public boolean isNative() { - return AccessFlag.NATIVE.isSet(getAccessFlagsValue()); - } - public boolean isStatic() { - return AccessFlag.STATIC.isSet(getAccessFlagsValue()); - } - public boolean isSynthetic() { - return AccessFlag.SYNTHETIC.isSet(getAccessFlagsValue()); - } - public boolean isAbstract() { - return AccessFlag.ABSTRACT.isSet(getAccessFlagsValue()); - } public boolean hasAccessFlag(AccessFlag accessFlag) { return accessFlag.isSet(getAccessFlagsValue()); } @@ -95,7 +67,7 @@ public boolean hasAccessFlag(AccessFlag flag1, AccessFlag flag2, AccessFlag flag } public abstract IdDefinition getDefinition(); - public abstract Key getKey(); + public abstract ProgramKey getKey(); public abstract IdItem getId(); public abstract DexClass getDexClass(); @@ -109,9 +81,6 @@ public void removeAccessFlag(AccessFlag accessFlag){ getDefinition().removeAccessFlag(accessFlag); } - int getAccessFlagsValue(){ - return getDefinition().getAccessFlagsValue(); - } public TypeKey getDefining(){ return getKey().getDeclaring(); } @@ -161,33 +130,8 @@ public boolean isInSameDirectory(DexDirectory 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; + public AccessibleProgram getProgramElement() { + return getDefinition(); } @Override diff --git a/src/main/java/com/reandroid/dex/model/DexField.java b/src/main/java/com/reandroid/dex/model/DexField.java index ae54838d7..83dd90cf2 100644 --- a/src/main/java/com/reandroid/dex/model/DexField.java +++ b/src/main/java/com/reandroid/dex/model/DexField.java @@ -20,17 +20,18 @@ import com.reandroid.dex.data.FieldDef; import com.reandroid.dex.ins.Opcode; import com.reandroid.dex.key.*; +import com.reandroid.dex.program.FieldProgram; import com.reandroid.dex.smali.SmaliWriter; import java.io.IOException; import java.util.Iterator; -public class DexField extends DexDeclaration { +public class DexField extends DexDeclaration implements FieldProgram { private final DexClass dexClass; private final FieldDef fieldDef; - public DexField(DexClass dexClass, FieldDef fieldDef){ + public DexField(DexClass dexClass, FieldDef fieldDef) { this.dexClass = dexClass; this.fieldDef = fieldDef; } @@ -42,18 +43,23 @@ public void setName(String name){ getId().setName(name); } - public Key getStaticInitialValue() { + @Override + public Key getStaticValue() { return getDefinition().getStaticValue(); } + public void setStaticValue(Key value) { + getDefinition().setStaticValue(value); + } + public IntegerReference getStaticValueIntegerReference() { - if (!(getStaticInitialValue() instanceof PrimitiveKey.IntegerKey)) { + if (!(getStaticValue() instanceof PrimitiveKey.IntegerKey)) { return null; } final DexField dexField = this; return new IntegerReference() { @Override public int get() { - Key key = dexField.getStaticInitialValue(); + Key key = dexField.getStaticValue(); if (key instanceof PrimitiveKey.IntegerKey) { return ((PrimitiveKey.IntegerKey) key).value(); } @@ -103,9 +109,6 @@ private IntegerReference resolveValueFromStaticConstructor() { } return null; } - public void setStaticValue(Key value) { - getDefinition().setStaticValue(value); - } @Override public FieldKey getKey(){ diff --git a/src/main/java/com/reandroid/dex/model/DexMethod.java b/src/main/java/com/reandroid/dex/model/DexMethod.java index 45d9f7a4f..4805948d0 100644 --- a/src/main/java/com/reandroid/dex/model/DexMethod.java +++ b/src/main/java/com/reandroid/dex/model/DexMethod.java @@ -24,6 +24,7 @@ import com.reandroid.dex.ins.Opcode; import com.reandroid.dex.ins.TryBlock; import com.reandroid.dex.key.*; +import com.reandroid.dex.program.MethodProgram; import com.reandroid.dex.smali.SmaliReader; import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.dex.smali.model.SmaliInstruction; @@ -34,7 +35,7 @@ import java.util.List; import java.util.function.Predicate; -public class DexMethod extends DexDeclaration { +public class DexMethod extends DexDeclaration implements MethodProgram { private final DexClass dexClass; private final MethodDef methodDef; @@ -273,18 +274,6 @@ public DexClass getDexClass() { public MethodDef getDefinition() { return methodDef; } - public boolean isConstructor() { - return AccessFlag.CONSTRUCTOR.isSet(getAccessFlagsValue()); - } - public boolean isBridge() { - return AccessFlag.BRIDGE.isSet(getAccessFlagsValue()); - } - public boolean isDirect(){ - return isConstructor() || isPrivate() || isStatic(); - } - public boolean isVirtual(){ - return !isDirect(); - } public Iterator getParameters(){ return ComputeIterator.of(getDefinition().getParameters(), diff --git a/src/main/java/com/reandroid/dex/model/DexMethodParameter.java b/src/main/java/com/reandroid/dex/model/DexMethodParameter.java index 939377bde..1b8c823d6 100644 --- a/src/main/java/com/reandroid/dex/model/DexMethodParameter.java +++ b/src/main/java/com/reandroid/dex/model/DexMethodParameter.java @@ -15,20 +15,18 @@ */ 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.program.MethodParameterProgram; +import com.reandroid.dex.program.ProgramElement; import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.utils.ObjectsUtil; -import com.reandroid.utils.collection.ComputeIterator; import java.io.IOException; import java.util.Iterator; -public class DexMethodParameter extends Dex implements AnnotatedDex { +public class DexMethodParameter extends Dex implements AnnotatedDex, MethodParameterProgram { private final DexMethod dexMethod; private final MethodParameter parameter; @@ -38,18 +36,19 @@ public DexMethodParameter(DexMethod dexMethod, MethodParameter parameter) { this.parameter = parameter; } - public String getDebugName(){ - return getParameter().getDebugName(); + @Override + public TypeKey getKey() { + return getParameter().getKey(); } - public void removeDebugName(){ - getParameter().setDebugName(null); + + @Override + public String getDebugName() { + return getParameter().getDebugName(); } - public void setDebugName(String name){ + @Override + public void setDebugName(String name) { getParameter().setDebugName(name); } - public void clearAnnotations(){ - getParameter().clearAnnotations(); - } public DexClass getTypeClass(){ return getClassRepository().getDexClass(getType()); } @@ -71,7 +70,7 @@ public boolean uses(Key key) { if(ObjectsUtil.equals(getType(), key)) { return true; } - Iterator iterator = getAnnotations(); + Iterator iterator = getDexAnnotations(); while (iterator.hasNext()){ DexAnnotation dexAnnotation = iterator.next(); if(dexAnnotation.uses(key)){ @@ -92,33 +91,8 @@ public void removeSelf() { } @Override - 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; + public ProgramElement getProgramElement() { + return getParameter(); } @Override diff --git a/src/main/java/com/reandroid/dex/model/RClass.java b/src/main/java/com/reandroid/dex/model/RClass.java index d50013e3d..c77d7edf7 100644 --- a/src/main/java/com/reandroid/dex/model/RClass.java +++ b/src/main/java/com/reandroid/dex/model/RClass.java @@ -18,13 +18,17 @@ import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.model.ResourceEntry; +import com.reandroid.dex.common.AccessFlag; import com.reandroid.dex.common.DexUtils; +import com.reandroid.dex.dalvik.DalvikEnclosingClass; +import com.reandroid.dex.dalvik.DalvikInnerClass; import com.reandroid.dex.id.ClassId; import com.reandroid.dex.data.ClassData; import com.reandroid.dex.data.FieldDef; import com.reandroid.dex.key.FieldKey; import com.reandroid.dex.key.TypeKey; import com.reandroid.utils.CompareUtil; +import com.reandroid.utils.StringsUtil; import com.reandroid.utils.collection.ArrayCollection; import com.reandroid.utils.collection.ComputeIterator; import com.reandroid.utils.collection.EmptyIterator; @@ -105,10 +109,38 @@ public void initialize(){ initializeAnnotations(); } - private void initializeAnnotations(){ - ClassId classId = getId(); - classId.getOrCreateDalvikEnclosingClass(); - classId.getOrCreateDalvikInnerClass(); + private void initializeAnnotations() { + ensureDalvikEnclosingClass(); + ensureDalvikInnerClass(); + } + + private void ensureDalvikInnerClass() { + TypeKey typeKey = getKey(); + if (typeKey == null) { + return; + } + String inner = typeKey.getSimpleInnerName(); + if(AccessFlag.SYNTHETIC.isSet(getAccessFlagsValue()) + || inner.equals(typeKey.getSimpleName()) + || StringsUtil.isDigits(inner)){ + inner = null; + } + DalvikInnerClass dalvikInnerClass = DalvikInnerClass.getOrCreate(this); + dalvikInnerClass.setName(inner); + dalvikInnerClass.setAccessFlags(getAccessFlagsValue()); + } + private void ensureDalvikEnclosingClass() { + TypeKey typeKey = getKey(); + if (typeKey == null) { + return; + } + TypeKey enclosing = typeKey.getEnclosingClass(); + if(typeKey.equals(enclosing)) { + return; + } + DalvikEnclosingClass dalvikEnclosingClass = DalvikEnclosingClass + .getOrCreate(this); + dalvikEnclosingClass.setEnclosing(enclosing); } @Override diff --git a/src/main/java/com/reandroid/dex/model/RClassParent.java b/src/main/java/com/reandroid/dex/model/RClassParent.java index 40f275cfb..4675dbfe5 100644 --- a/src/main/java/com/reandroid/dex/model/RClassParent.java +++ b/src/main/java/com/reandroid/dex/model/RClassParent.java @@ -18,20 +18,16 @@ import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.model.ResourceEntry; import com.reandroid.dex.common.AccessFlag; -import com.reandroid.dex.common.AnnotationVisibility; import com.reandroid.dex.common.DexUtils; +import com.reandroid.dex.dalvik.DalvikMemberClass; import com.reandroid.dex.id.ClassId; 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.utils.CompareUtil; import com.reandroid.utils.collection.ArrayCollection; -import com.reandroid.utils.collection.CollectionUtil; -import com.reandroid.utils.collection.ComputeIterator; import com.reandroid.utils.io.IOUtil; import org.xmlpull.v1.XmlSerializer; @@ -87,33 +83,8 @@ public RClass getOrCreateMember(String simpleName){ rClass.initialize(); return rClass; } - public void addMemberAnnotation(String simpleName){ - if(CollectionUtil.contains(getMemberSimpleNames(), simpleName)) { - return; - } - 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; - } - ArrayValueKey arrayValueKey = ArrayValueKey.EMPTY; - element.setValue(arrayValueKey); - return arrayValueKey; + public void addMemberAnnotation(String simpleName) { + DalvikMemberClass.getOrCreate(this).addSimpleName(simpleName); } public void initialize(){ ClassId classId = getId(); diff --git a/src/main/java/com/reandroid/dex/program/AccessibleProgram.java b/src/main/java/com/reandroid/dex/program/AccessibleProgram.java new file mode 100644 index 000000000..c93aa8fd2 --- /dev/null +++ b/src/main/java/com/reandroid/dex/program/AccessibleProgram.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.program; + +import com.reandroid.dex.common.AccessFlag; +import com.reandroid.dex.common.Modifier; + +import java.util.Iterator; + +public interface AccessibleProgram extends ProgramElement { + + int getAccessFlagsValue(); + void setAccessFlagsValue(int value); + + default boolean isPublic() { + return AccessFlag.PUBLIC.isSet(getElementType(), getAccessFlagsValue()); + } + default boolean isPrivate() { + return AccessFlag.PRIVATE.isSet(getElementType(), getAccessFlagsValue()); + } + default boolean isInternal() { + return (getAccessFlagsValue() & 0x7) == 0; + } + default boolean isStatic() { + return AccessFlag.STATIC.isSet(getElementType(), getAccessFlagsValue()); + } + default boolean isFinal() { + return AccessFlag.FINAL.isSet(getElementType(), getAccessFlagsValue()); + } + default boolean isProtected() { + return AccessFlag.PROTECTED.isSet(getAccessFlagsValue()); + } + default boolean isNative() { + return AccessFlag.NATIVE.isSet(getAccessFlagsValue()); + } + default boolean isSynthetic() { + return AccessFlag.SYNTHETIC.isSet(getAccessFlagsValue()); + } + default boolean isAbstract() { + return AccessFlag.ABSTRACT.isSet(getAccessFlagsValue()); + } + + default Iterator getModifiers(){ + return getAccessFlags(); + } + default void addAccessFlag(AccessFlag flag) { + int current = getAccessFlagsValue(); + int value = flag.getValue(); + if((value & 0x7) != 0){ + current = current & ~0x7; + } + setAccessFlagsValue(current | value); + } + default Iterator getAccessFlags() { + return AccessFlag.valuesOf(getElementType(), getAccessFlagsValue()); + } + default void removeAccessFlag(AccessFlag flag) { + setAccessFlagsValue(getAccessFlagsValue() & ~flag.getValue()); + } +} diff --git a/src/main/java/com/reandroid/dex/common/AnnotatedItem.java b/src/main/java/com/reandroid/dex/program/AnnotatedProgram.java similarity index 96% rename from src/main/java/com/reandroid/dex/common/AnnotatedItem.java rename to src/main/java/com/reandroid/dex/program/AnnotatedProgram.java index c368f2b3f..1f9a83d6c 100644 --- a/src/main/java/com/reandroid/dex/common/AnnotatedItem.java +++ b/src/main/java/com/reandroid/dex/program/AnnotatedProgram.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.reandroid.dex.common; +package com.reandroid.dex.program; import com.reandroid.dex.key.AnnotationItemKey; import com.reandroid.dex.key.AnnotationSetKey; @@ -22,7 +22,7 @@ import java.util.function.Predicate; -public interface AnnotatedItem { +public interface AnnotatedProgram { AnnotationSetKey getAnnotation(); void setAnnotation(AnnotationSetKey annotationSet); diff --git a/src/main/java/com/reandroid/dex/program/ClassProgram.java b/src/main/java/com/reandroid/dex/program/ClassProgram.java new file mode 100644 index 000000000..49574b66c --- /dev/null +++ b/src/main/java/com/reandroid/dex/program/ClassProgram.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.program; + +import com.reandroid.dex.key.TypeKey; +import com.reandroid.dex.key.TypeListKey; + +import java.lang.annotation.ElementType; +import java.util.Iterator; + +public interface ClassProgram extends AccessibleProgram { + + @Override + TypeKey getKey(); + TypeKey getSuperClassKey(); + String getSourceFileName(); + + TypeListKey getInterfacesKey(); + + Iterator getStaticFields(); + Iterator getInstanceFields(); + + Iterator getDirectMethods(); + Iterator getVirtualMethods(); + + @Override + default ElementType getElementType() { + return ElementType.TYPE; + } +} diff --git a/src/main/java/com/reandroid/dex/program/FieldProgram.java b/src/main/java/com/reandroid/dex/program/FieldProgram.java new file mode 100644 index 000000000..d130db605 --- /dev/null +++ b/src/main/java/com/reandroid/dex/program/FieldProgram.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.program; + +import com.reandroid.dex.key.FieldKey; +import com.reandroid.dex.key.Key; + +import java.lang.annotation.ElementType; + +public interface FieldProgram extends AccessibleProgram { + + @Override + FieldKey getKey(); + Key getStaticValue(); + + @Override + default ElementType getElementType() { + return ElementType.FIELD; + } + default boolean isInstance() { + return !isStatic(); + } +} diff --git a/src/main/java/com/reandroid/dex/program/MethodParameterProgram.java b/src/main/java/com/reandroid/dex/program/MethodParameterProgram.java new file mode 100644 index 000000000..f3e6184ce --- /dev/null +++ b/src/main/java/com/reandroid/dex/program/MethodParameterProgram.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.program; + +import java.lang.annotation.ElementType; + +public interface MethodParameterProgram extends ProgramElement { + + String getDebugName(); + void setDebugName(String name); + + @Override + default ElementType getElementType() { + return ElementType.PARAMETER; + } +} diff --git a/src/main/java/com/reandroid/dex/program/MethodProgram.java b/src/main/java/com/reandroid/dex/program/MethodProgram.java new file mode 100644 index 000000000..16594223c --- /dev/null +++ b/src/main/java/com/reandroid/dex/program/MethodProgram.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.program; + +import com.reandroid.dex.common.AccessFlag; +import com.reandroid.dex.key.MethodKey; + +import java.lang.annotation.ElementType; + +public interface MethodProgram extends AccessibleProgram { + + @Override + MethodKey getKey(); + @Override + default ElementType getElementType() { + return ElementType.METHOD; + } + + default boolean isConstructor() { + return AccessFlag.CONSTRUCTOR.isSet(getAccessFlagsValue()); + } + default boolean isBridge() { + return AccessFlag.BRIDGE.isSet(getAccessFlagsValue()); + } + default boolean isDirect() { + return isConstructor() || isStatic() || isPrivate(); + } + default boolean isVirtual(){ + return !isDirect(); + } +} diff --git a/src/main/java/com/reandroid/dex/program/ProgramElement.java b/src/main/java/com/reandroid/dex/program/ProgramElement.java new file mode 100644 index 000000000..fa8351adf --- /dev/null +++ b/src/main/java/com/reandroid/dex/program/ProgramElement.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.dex.program; + +import com.reandroid.dex.key.ProgramKey; + +import java.lang.annotation.ElementType; + +public interface ProgramElement extends AnnotatedProgram { + ProgramKey getKey(); + ElementType getElementType(); +} diff --git a/src/main/java/com/reandroid/dex/reference/TypeListReference.java b/src/main/java/com/reandroid/dex/reference/TypeListReference.java index 981a0c585..c657489d2 100644 --- a/src/main/java/com/reandroid/dex/reference/TypeListReference.java +++ b/src/main/java/com/reandroid/dex/reference/TypeListReference.java @@ -18,6 +18,7 @@ import com.reandroid.dex.common.SectionItem; import com.reandroid.dex.data.TypeList; import com.reandroid.dex.id.TypeId; +import com.reandroid.dex.key.Key; import com.reandroid.dex.key.TypeKey; import com.reandroid.dex.key.TypeListKey; import com.reandroid.dex.sections.SectionType; @@ -50,6 +51,16 @@ public Iterator getTypeKeys() { public TypeListKey getKey() { return (TypeListKey) super.getKey(); } + + @Override + public void setKey(Key key) { + TypeListKey typeListKey = (TypeListKey) key; + if (typeListKey != null && typeListKey.isEmpty()) { + key = null; + } + super.setKey(key); + } + public void add(TypeKey typeKey){ TypeListKey key = getKey(); if (key != null) { diff --git a/src/main/java/com/reandroid/dex/resource/R.java b/src/main/java/com/reandroid/dex/resource/R.java index 08baa8202..299bbd37c 100644 --- a/src/main/java/com/reandroid/dex/resource/R.java +++ b/src/main/java/com/reandroid/dex/resource/R.java @@ -17,8 +17,7 @@ import com.reandroid.apk.XmlHelper; import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.dex.key.ArrayKey; -import com.reandroid.dex.key.Key; +import com.reandroid.dex.dalvik.DalvikMemberClass; import com.reandroid.dex.key.TypeKey; import com.reandroid.dex.model.*; import com.reandroid.dex.smali.SmaliWriter; @@ -123,26 +122,12 @@ boolean isChild(DexClass child) { return typeKey.equals(childKey.getEnclosingClass()); } private boolean containsOnMembers(TypeKey typeKey) { - ArrayKey valueArray = getDalvikMemberClasses(); - if(valueArray != null) { - return CollectionUtil.contains(valueArray.iterator(), typeKey); + DalvikMemberClass dalvikMemberClass = DalvikMemberClass.of(getDexClass()); + if (dalvikMemberClass != null) { + return dalvikMemberClass.contains(typeKey); } return false; } - private ArrayKey getDalvikMemberClasses() { - DexAnnotation annotation = getDexClass() - .getAnnotation(TypeKey.DALVIK_MemberClass); - if(annotation != null) { - DexAnnotationElement element = annotation.get("value"); - if(element != null) { - Key value = element.getValue(); - if(value instanceof ArrayKey) { - return (ArrayKey) value; - } - } - } - return null; - } public String getName() { return getKey().getSimpleInnerName(); diff --git a/src/main/java/com/reandroid/dex/sections/DexLayoutBlock.java b/src/main/java/com/reandroid/dex/sections/DexLayoutBlock.java index 5245e9bf2..848ebed30 100644 --- a/src/main/java/com/reandroid/dex/sections/DexLayoutBlock.java +++ b/src/main/java/com/reandroid/dex/sections/DexLayoutBlock.java @@ -116,10 +116,8 @@ private void loadInterfacesMap(){ return; } for (ClassId classId : section) { - Iterator interfaceKeys = classId.getInterfaceKeys(); - while (interfaceKeys.hasNext()){ - TypeKey typeKey = interfaceKeys.next(); - if(!DexUtils.isJavaFramework(typeKey.getTypeName())) { + for (TypeKey typeKey : classId.getInterfacesKey()) { + if (!DexUtils.isJavaFramework(typeKey.getTypeName())) { interfaceMap.put(typeKey, classId); } } diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliClass.java b/src/main/java/com/reandroid/dex/smali/model/SmaliClass.java index e427e8e48..fa5cdc055 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliClass.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliClass.java @@ -21,15 +21,17 @@ import com.reandroid.dex.key.StringKey; import com.reandroid.dex.key.TypeKey; import com.reandroid.dex.key.TypeListKey; +import com.reandroid.dex.program.ClassProgram; import com.reandroid.dex.smali.SmaliDirective; import com.reandroid.dex.smali.SmaliParseException; import com.reandroid.dex.smali.SmaliReader; import com.reandroid.dex.smali.SmaliWriter; import java.io.IOException; +import java.lang.annotation.ElementType; import java.util.Iterator; -public class SmaliClass extends SmaliDef{ +public class SmaliClass extends SmaliDef implements ClassProgram { private TypeKey superClass; private StringKey sourceFile; @@ -50,6 +52,11 @@ public SmaliClass(){ methods.setParent(this); } + @Override + public ElementType getElementType() { + return ElementType.TYPE; + } + @Override public TypeKey getKey() { return TypeKey.create(getName()); @@ -64,29 +71,36 @@ public void setKey(TypeKey key) { setName(name); } - public TypeKey getSuperClass() { + @Override + public TypeKey getSuperClassKey() { return superClass; } public void setSuperClass(TypeKey typeKey) { this.superClass = typeKey; } - public StringKey getSourceFile() { - return sourceFile; - } - public void setSourceFile(StringKey sourceFile) { - this.sourceFile = sourceFile; - } + @Override public String getSourceFileName() { - StringKey key = getSourceFile(); - if(key != null){ + StringKey key = getSourceFileKey(); + if (key != null) { return key.getString(); } return null; } + public StringKey getSourceFileKey() { + return sourceFile; + } + public void setSourceFile(String sourceFile) { + StringKey key = sourceFile == null ? null : StringKey.create(sourceFile); + setSourceFile(key); + } + public void setSourceFile(StringKey sourceFile) { + this.sourceFile = sourceFile; + } public SmaliInterfaceSet getInterfaces() { return interfaces; } - public TypeListKey getInterfacesKey(){ + @Override + public TypeListKey getInterfacesKey() { return getInterfaces().getKey(); } public void setInterfaces(TypeListKey key){ @@ -95,18 +109,22 @@ public void setInterfaces(TypeListKey key){ public boolean hasClassData(){ return !fields.isEmpty() || !methods.isEmpty(); } + @Override public Iterator getStaticFields(){ return fields.getStaticFields(); } + @Override public Iterator getInstanceFields(){ return fields.getInstanceFields(); } public void addFields(Iterator iterator) { fields.addAll(iterator); } + @Override public Iterator getDirectMethods(){ return methods.getDirectMethods(); } + @Override public Iterator getVirtualMethods(){ return methods.getVirtualMethods(); } @@ -144,8 +162,8 @@ public void append(SmaliWriter writer) throws IOException { writer.appendOptional(getKey()); writer.newLine(); SmaliDirective.SUPER.append(writer); - writer.appendOptional(getSuperClass()); - StringKey source = getSourceFile(); + writer.appendOptional(getSuperClassKey()); + StringKey source = getSourceFileKey(); if(source != null){ writer.newLine(); SmaliDirective.SOURCE.append(writer); @@ -191,7 +209,7 @@ private boolean parseNext(SmaliReader reader) throws IOException { return true; } if(directive == SmaliDirective.ANNOTATION){ - getOrCreateAnnotation().parse(reader); + getOrCreateSmaliAnnotationSet().parse(reader); return true; } if(directive == SmaliDirective.FIELD){ diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliDef.java b/src/main/java/com/reandroid/dex/smali/model/SmaliDef.java index d2dac174e..576b3d4f8 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliDef.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliDef.java @@ -19,20 +19,18 @@ import com.reandroid.dex.common.HiddenApiFlag; import com.reandroid.dex.common.Modifier; import com.reandroid.dex.key.*; +import com.reandroid.dex.program.AccessibleProgram; import com.reandroid.dex.smali.SmaliDirective; -import com.reandroid.dex.smali.SmaliReader; import com.reandroid.dex.smali.SmaliRegion; import com.reandroid.utils.collection.ArrayIterator; -import com.reandroid.utils.collection.CollectionUtil; -import java.io.IOException; import java.util.Iterator; -import java.util.List; -public abstract class SmaliDef extends Smali implements SmaliRegion { +public abstract class SmaliDef extends Smali implements AccessibleProgram, SmaliRegion { private StringKey name; - private AccessFlag[] accessFlags; + private int accessFlagsValue; + private SmaliAnnotationSet annotation; private HiddenApiFlag[] hiddenApiFlags; @@ -43,25 +41,48 @@ public SmaliDef(){ super(); } - public abstract Key getKey(); - public AccessFlag[] getAccessFlags() { - return accessFlags; + @Override + public abstract ProgramKey getKey(); + + @Override + public int getAccessFlagsValue() { + return accessFlagsValue; } - public void setAccessFlags(AccessFlag[] accessFlags) { - this.accessFlags = accessFlags; + @Override + public void setAccessFlagsValue(int accessFlagsValue) { + this.accessFlagsValue = accessFlagsValue; } - public void setAccessFlags(Iterator iterator) { - AccessFlag[] accessFlags; - if (!iterator.hasNext()) { - accessFlags = null; + @Override + public AnnotationSetKey getAnnotation() { + SmaliAnnotationSet annotationSet = getAnnotationSet(); + if (annotationSet != null) { + return annotationSet.getKey(); + } + return AnnotationSetKey.EMPTY; + } + @Override + public void setAnnotation(AnnotationSetKey annotation) { + if (annotation == null || annotation.isEmpty()) { + setSmaliAnnotationSet(null); } else { - List list = CollectionUtil.toList(iterator); - accessFlags = list.toArray(new AccessFlag[list.size()]); + getOrCreateSmaliAnnotationSet().setKey(annotation); } - setAccessFlags(accessFlags); } - public int getAccessFlagsValue(){ - return Modifier.combineValues(getAccessFlags()); + @Override + public boolean hasAnnotations() { + SmaliAnnotationSet annotationSet = getAnnotationSet(); + return annotationSet != null && !annotationSet.isEmpty(); + } + @Override + public void clearAnnotations() { + setSmaliAnnotationSet(null); + } + + public void setAccessFlags(AccessFlag[] accessFlags) { + setAccessFlagsValue(Modifier.combineValues(accessFlags)); + } + public void setAccessFlags(Iterator iterator) { + setAccessFlagsValue(Modifier.combineValues(iterator)); } public Iterator getHiddenApiFlags() { return ArrayIterator.of(hiddenApiFlags()); @@ -111,46 +132,29 @@ public AnnotationSetKey getAnnotationSetKey() { } return null; } - public void setAnnotation(AnnotationSetKey annotation) { - if (annotation != null) { - setAnnotation(annotation.iterator()); - } else { - setAnnotation((SmaliAnnotationSet) null); - } - } public void setAnnotation(Iterator iterator) { if (iterator.hasNext()) { - getOrCreateAnnotation().addAllKeys(iterator); + getOrCreateSmaliAnnotationSet().addAllKeys(iterator); } else { - setAnnotation((SmaliAnnotationSet) null); - } - } - public void addAnnotation(AnnotationSetKey annotation) { - SmaliAnnotationSet annotationSet = getOrCreateAnnotation(); - annotationSet.addAllKeys(annotation); - } - - public void addAnnotations(Iterator iterator) { - if (iterator.hasNext()) { - getOrCreateAnnotation().addAllKeys(iterator); + setSmaliAnnotationSet(null); } } public void addAnnotation(AnnotationItemKey annotation) { - SmaliAnnotationSet annotationSet = getOrCreateAnnotation(); + SmaliAnnotationSet annotationSet = getOrCreateSmaliAnnotationSet(); annotationSet.addKey(annotation); } public SmaliAnnotationSet getAnnotationSet() { return annotation; } - public SmaliAnnotationSet getOrCreateAnnotation() { + public SmaliAnnotationSet getOrCreateSmaliAnnotationSet() { SmaliAnnotationSet directory = getAnnotationSet(); if(directory == null){ directory = new SmaliAnnotationSet(); - setAnnotation(directory); + setSmaliAnnotationSet(directory); } return directory; } - public void setAnnotation(SmaliAnnotationSet annotation) { + public void setSmaliAnnotationSet(SmaliAnnotationSet annotation) { SmaliAnnotationSet old = this.annotation; this.annotation = annotation; if (annotation != null) { @@ -169,16 +173,6 @@ public SmaliDirective getSmaliDirective() { return null; } - public boolean isStatic(){ - return Modifier.contains(getAccessFlags(), AccessFlag.STATIC); - } - public boolean isFinal(){ - return Modifier.contains(getAccessFlags(), AccessFlag.FINAL); - } - public boolean isPrivate(){ - return Modifier.contains(getAccessFlags(), AccessFlag.PRIVATE); - } - private SmaliDefSet getDefSet(){ return getParentInstance(SmaliDefSet.class); } @@ -188,8 +182,4 @@ public SmaliClass getSmaliClass(){ } return getParentInstance(SmaliClass.class); } - - public SmaliAnnotationItem parseAnnotation(SmaliReader reader) throws IOException { - return getOrCreateAnnotation().parseNext(reader); - } } diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliField.java b/src/main/java/com/reandroid/dex/smali/model/SmaliField.java index a2c9335e3..d41e7580f 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliField.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliField.java @@ -22,6 +22,7 @@ import com.reandroid.dex.key.Key; import com.reandroid.dex.key.StringKey; import com.reandroid.dex.key.TypeKey; +import com.reandroid.dex.program.FieldProgram; import com.reandroid.dex.smali.SmaliDirective; import com.reandroid.dex.smali.SmaliParseException; import com.reandroid.dex.smali.SmaliReader; @@ -30,7 +31,7 @@ import java.io.IOException; import java.util.Iterator; -public class SmaliField extends SmaliDef{ +public class SmaliField extends SmaliDef implements FieldProgram { private TypeKey type; private SmaliValue value; @@ -64,14 +65,23 @@ public void setType(TypeKey type) { this.type = type; } + @Override + public Key getStaticValue() { + SmaliValue value = getValue(); + if (value != null) { + return value.getKey(); + } + return null; + } + public void setStaticValue(Key key) { + setStaticValue(SmaliValueFactory.createForValue(key)); + } + public SmaliValue getValue() { return value; } - public void setValue(Key key) { - setValue(SmaliValueFactory.createForValue(key)); - } - public void setValue(SmaliValue value) { + public void setStaticValue(SmaliValue value) { SmaliValue oldValue = this.value; this.value = value; if (value != null) { @@ -91,7 +101,7 @@ void fixUninitializedFinalValue() { return; } if(!isInitializedInStaticConstructor(smaliClass, fieldKey)) { - setValue(SmaliValueFactory.createForField(fieldKey.getType())); + setStaticValue(SmaliValueFactory.createForField(fieldKey.getType())); } } private boolean isInitializedInStaticConstructor(SmaliClass smaliClass, FieldKey fieldKey) { @@ -114,10 +124,6 @@ public SmaliDirective getSmaliDirective() { return SmaliDirective.FIELD; } - public boolean isInstance(){ - return !isStatic(); - } - @Override public void append(SmaliWriter writer) throws IOException { getSmaliDirective().append(writer); @@ -163,7 +169,7 @@ private void parseValue(SmaliReader reader) throws IOException { reader.skip(1); // = reader.skipWhitespaces(); SmaliValue value = SmaliValueFactory.create(reader); - setValue(value); + setStaticValue(value); value.parse(reader); } private void parseAnnotationSet(SmaliReader reader) throws IOException { @@ -178,7 +184,7 @@ private void parseAnnotationSet(SmaliReader reader) throws IOException { annotationSet.parse(reader); reader.skipWhitespacesOrComment(); if(getSmaliDirective().isEnd(reader)){ - setAnnotation(annotationSet); + setSmaliAnnotationSet(annotationSet); SmaliDirective.parse(reader); }else { // put back, it is method annotation diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliInterfaceSet.java b/src/main/java/com/reandroid/dex/smali/model/SmaliInterfaceSet.java index 957f5f9e7..427b6b262 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliInterfaceSet.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliInterfaceSet.java @@ -34,7 +34,7 @@ public SmaliInterfaceSet(){ public TypeListKey getKey(){ int size = size(); if(size == 0){ - return null; + return TypeListKey.EMPTY; } TypeKey[] keys = new TypeKey[size]; for (int i = 0; i < size; i++) { diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliMethod.java b/src/main/java/com/reandroid/dex/smali/model/SmaliMethod.java index 07faf254f..0f2b63dd5 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliMethod.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliMethod.java @@ -20,6 +20,7 @@ import com.reandroid.dex.common.Modifier; import com.reandroid.dex.common.RegistersTable; import com.reandroid.dex.key.*; +import com.reandroid.dex.program.MethodProgram; import com.reandroid.dex.smali.SmaliDirective; import com.reandroid.dex.smali.SmaliParseException; import com.reandroid.dex.smali.SmaliReader; @@ -31,7 +32,7 @@ import java.io.IOException; import java.util.Iterator; -public class SmaliMethod extends SmaliDef implements RegistersTable{ +public class SmaliMethod extends SmaliDef implements MethodProgram, RegistersTable { private ProtoKey protoKey; @@ -108,17 +109,6 @@ public SmaliDirective getSmaliDirective() { return SmaliDirective.METHOD; } - - public boolean isConstructor(){ - return Modifier.contains(getAccessFlags(), AccessFlag.CONSTRUCTOR); - } - public boolean isDirect(){ - return isConstructor() || isStatic() || isPrivate(); - } - public boolean isVirtual(){ - return !isDirect(); - } - @Override public void append(SmaliWriter writer) throws IOException { getSmaliDirective().append(writer); @@ -168,7 +158,7 @@ private boolean parseNoneCode(SmaliReader reader) throws IOException { return true; } if(directive == SmaliDirective.ANNOTATION){ - getOrCreateAnnotation().parse(reader); + getOrCreateSmaliAnnotationSet().parse(reader); return true; } if(directive == SmaliDirective.PARAM){ diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliMethodParameter.java b/src/main/java/com/reandroid/dex/smali/model/SmaliMethodParameter.java index 0fc6ab099..5058b86be 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliMethodParameter.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliMethodParameter.java @@ -15,25 +15,45 @@ */ package com.reandroid.dex.smali.model; -import com.reandroid.dex.key.AnnotationItemKey; -import com.reandroid.dex.key.AnnotationSetKey; -import com.reandroid.dex.key.ProtoKey; -import com.reandroid.dex.key.StringKey; +import com.reandroid.dex.key.*; +import com.reandroid.dex.program.MethodParameterProgram; import com.reandroid.dex.smali.*; +import com.reandroid.utils.StringsUtil; import java.io.IOException; -public class SmaliMethodParameter extends SmaliDebug implements SmaliRegion { +public class SmaliMethodParameter extends SmaliDebug implements MethodParameterProgram, SmaliRegion { private final SmaliRegisterSet registerSet; private StringKey name; private SmaliAnnotationSet annotationSet; - public SmaliMethodParameter(){ + public SmaliMethodParameter() { super(); registerSet = new SmaliRegisterSet(); } + @Override + public TypeKey getKey(){ + SmaliMethod smaliMethod = getParentInstance(SmaliMethod.class); + if(smaliMethod == null){ + return null; + } + ProtoKey protoKey = smaliMethod.getProtoKey(); + if(protoKey == null){ + return null; + } + SmaliRegister smaliRegister = getSmaliRegister(); + if(smaliRegister == null){ + return null; + } + int index = smaliRegister.getNumber(); + if(!smaliMethod.isStatic()){ + index = index - 1; + } + return protoKey.getParameter(protoKey.getParameterIndex(index)); + } + public SmaliRegister getSmaliRegister(){ SmaliRegisterSet registerSet = getRegisterSet(); if(registerSet.isEmpty()){ @@ -51,29 +71,56 @@ public StringKey getNameKey() { public void setName(StringKey name) { this.name = name; } - public String getName() { + @Override + public String getDebugName() { StringKey key = getNameKey(); if(key != null){ return key.getString(); } return null; } - - public boolean hasAnnotations(){ - SmaliAnnotationSet annotationSet = getAnnotationSet(); - return annotationSet != null && !annotationSet.isEmpty(); + @Override + public void setDebugName(String name) { + if (StringsUtil.isEmpty(name)) { + name = null; + } + StringKey key = name == null ? null : StringKey.create(name); + setName(key); } - public AnnotationSetKey getAnnotations() { - SmaliAnnotationSet annotationSet = getAnnotationSet(); + + @Override + public AnnotationSetKey getAnnotation() { + SmaliAnnotationSet annotationSet = getSmaliAnnotationSet(); if (annotationSet != null) { return annotationSet.getKey(); } return AnnotationSetKey.EMPTY; } - public SmaliAnnotationSet getAnnotationSet() { + @Override + public void setAnnotation(AnnotationSetKey annotation) { + if (annotation == null || annotation.isEmpty()) { + setSmaliAnnotationSet(null); + } else { + getOrCreateSmaliAnnotationSet().setKey(annotation); + } + } + @Override + public void clearAnnotations() { + setSmaliAnnotationSet(null); + } + + public SmaliAnnotationSet getSmaliAnnotationSet() { + return annotationSet; + } + public SmaliAnnotationSet getOrCreateSmaliAnnotationSet() { + SmaliAnnotationSet annotationSet = getSmaliAnnotationSet(); + if (annotationSet == null) { + annotationSet = new SmaliAnnotationSet(); + setSmaliAnnotationSet(annotationSet); + } return annotationSet; } - public void setAnnotationSet(SmaliAnnotationSet annotationSet) { + public void setSmaliAnnotationSet(SmaliAnnotationSet annotationSet) { this.annotationSet = annotationSet; if(annotationSet != null){ annotationSet.setParent(this); @@ -114,7 +161,7 @@ public void append(SmaliWriter writer) throws IOException { writer.append(", "); name.append(writer); } - SmaliAnnotationSet annotationSet = getAnnotationSet(); + SmaliAnnotationSet annotationSet = getSmaliAnnotationSet(); if(annotationSet != null){ writer.indentPlus(); writer.newLine(); @@ -135,7 +182,7 @@ public void parse(SmaliReader reader) throws IOException { } parseName(reader); parseAnnotationSet(reader); - AnnotationItemKey duplicate = getAnnotations().getDuplicate(); + AnnotationItemKey duplicate = getAnnotation().getDuplicate(); if (duplicate != null) { throw new SmaliParseException("Multiple annotation of type: " + duplicate.getType() + "\n", reader); @@ -158,7 +205,7 @@ private void parseAnnotationSet(SmaliReader reader) throws IOException { annotationSet.parse(reader); reader.skipWhitespacesOrComment(); if(getSmaliDirective().isEnd(reader)){ - setAnnotationSet(annotationSet); + setSmaliAnnotationSet(annotationSet); SmaliDirective.parse(reader); }else { // put back, it is method annotation diff --git a/src/main/java/com/reandroid/graph/InlineFieldIntResolver.java b/src/main/java/com/reandroid/graph/InlineFieldIntResolver.java index 814f1dd0d..32186f2a4 100644 --- a/src/main/java/com/reandroid/graph/InlineFieldIntResolver.java +++ b/src/main/java/com/reandroid/graph/InlineFieldIntResolver.java @@ -84,7 +84,7 @@ private Key getValueFromStaticField(DexInstruction instruction) { if(dexField == null) { return null; } - return dexField.getStaticInitialValue(); + return dexField.getStaticValue(); } private void resolve(DexInstruction instruction, Key value) { if (!(value instanceof PrimitiveKey)) {