diff --git a/src/main/java/com/reandroid/dex/common/DexUtils.java b/src/main/java/com/reandroid/dex/common/DexUtils.java index 5dc0b42f9..f73b49910 100644 --- a/src/main/java/com/reandroid/dex/common/DexUtils.java +++ b/src/main/java/com/reandroid/dex/common/DexUtils.java @@ -17,6 +17,7 @@ package com.reandroid.dex.common; import com.reandroid.dex.key.TypeKey; +import com.reandroid.utils.HexUtil; import com.reandroid.utils.NumbersUtil; import com.reandroid.utils.StringsUtil; import com.reandroid.utils.collection.ArrayCollection; @@ -277,6 +278,10 @@ private static void escapeChar(Appendable appendable, char c) throws IOException appendable.append(Character.forDigit((c >> 4) & 0x0f, 16)); appendable.append(Character.forDigit(c & 0x0f, 16)); } + /** + * Use StringKey.decodeEscapedString + * */ + @Deprecated public static String decodeString(String text) { if(text.indexOf('\\') < 0){ return text; @@ -324,19 +329,19 @@ private static char getEscaped(char ch){ private static Character nextHex(String text, int start){ int length = text.length(); int end = start + 4; - if(end > length){ + if (end > length) { return null; } - StringBuilder builder = new StringBuilder(4); - for(int i = start; i < end; i++){ - builder.append(text.charAt(i)); - } - try{ - int i = Integer.parseInt(builder.toString(), 16); - return (char) i; - }catch (NumberFormatException ignored){ - return null; + int value = 0; + for (int i = start; i < end; i++) { + int v = HexUtil.decodeHexChar(text.charAt(i)); + if (v == -1) { + return null; + } + value = value << 4; + value = value | v; } + return (char) value; } public static boolean isJavaFramework(String name){ return name.startsWith("Ljava/"); diff --git a/src/main/java/com/reandroid/dex/data/AnnotationElement.java b/src/main/java/com/reandroid/dex/data/AnnotationElement.java index 5fc71c087..ee54388c5 100644 --- a/src/main/java/com/reandroid/dex/data/AnnotationElement.java +++ b/src/main/java/com/reandroid/dex/data/AnnotationElement.java @@ -1,3 +1,18 @@ +/* + * 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.data; import com.reandroid.arsc.base.Creator; diff --git a/src/main/java/com/reandroid/dex/data/FieldDef.java b/src/main/java/com/reandroid/dex/data/FieldDef.java index 1ea556568..59a4dc159 100644 --- a/src/main/java/com/reandroid/dex/data/FieldDef.java +++ b/src/main/java/com/reandroid/dex/data/FieldDef.java @@ -112,7 +112,7 @@ private void appendStaticValue(SmaliWriter writer) throws IOException { private boolean isNonDefaultValue(Key key) { if (key instanceof PrimitiveKey) { PrimitiveKey primitiveKey = (PrimitiveKey) key; - return primitiveKey.asLongValue() != 0; + return primitiveKey.getValueAsLong() != 0; } return !(key instanceof NullKey); } diff --git a/src/main/java/com/reandroid/dex/id/FieldId.java b/src/main/java/com/reandroid/dex/id/FieldId.java index 7df2d67c3..c2aa53794 100644 --- a/src/main/java/com/reandroid/dex/id/FieldId.java +++ b/src/main/java/com/reandroid/dex/id/FieldId.java @@ -22,12 +22,12 @@ import com.reandroid.dex.sections.SectionType; import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.utils.CompareUtil; +import com.reandroid.utils.ObjectsUtil; import com.reandroid.utils.collection.CombiningIterator; import com.reandroid.utils.collection.SingleIterator; import java.io.IOException; import java.util.Iterator; -import java.util.Objects; public class FieldId extends IdItem implements Comparable{ private final IdItemIndirectReference defining; @@ -53,7 +53,13 @@ public Iterator usedIds(){ public String getName() { return nameReference.getString(); } - public void setName(String name){ + public StringKey getNameKey() { + return nameReference.getKey(); + } + public void setName(StringKey name) { + this.nameReference.setKey(name); + } + public void setName(String name) { this.nameReference.setString(name); } public StringId getNameId(){ @@ -113,8 +119,9 @@ public SectionType getSectionType(){ return SectionType.FIELD_ID; } @Override - public FieldKey getKey(){ - return checkKey(FieldKey.create(this)); + public FieldKey getKey() { + return checkKey(FieldKey.create(getDefining(), + getNameKey(), getFieldType())); } @Override @@ -123,11 +130,11 @@ public void setKey(Key key){ } public void setKey(FieldKey key){ FieldKey old = getKey(); - if(Objects.equals(key, old)){ + if (ObjectsUtil.equals(key, old)) { return; } defining.setKey(key.getDeclaring()); - nameReference.setString(key.getName()); + nameReference.setKey(key.getNameKey()); fieldType.setKey(key.getType()); keyChanged(old); } @@ -161,9 +168,9 @@ public int compareTo(FieldId fieldId) { return CompareUtil.compare(getFieldTypeId(), fieldId.getFieldTypeId()); } @Override - public String toString(){ + public String toString() { FieldKey key = getKey(); - if(key != null){ + if(key != null) { return key.toString(); } return getDefiningId() + "->" + getNameId() + ":" + getFieldTypeId(); diff --git a/src/main/java/com/reandroid/dex/ins/InsArrayDataList.java b/src/main/java/com/reandroid/dex/ins/InsArrayDataList.java index 5e1f6cf4d..c6cd72cd1 100644 --- a/src/main/java/com/reandroid/dex/ins/InsArrayDataList.java +++ b/src/main/java/com/reandroid/dex/ins/InsArrayDataList.java @@ -260,7 +260,7 @@ public ArrayDataEntry(int width) { } public void fromSmali(SmaliValueX smaliValueX) { - set(smaliValueX.asLongValue()); + set(smaliValueX.getValueAsLong()); } public SmaliValueX toSmali() { return new SmaliValueX(width(), getLong()); @@ -322,7 +322,7 @@ public String toString() { builder.append('t'); } else if (width == 2) { builder.append('S'); - } else if (width == 8 && hex.length() > 10) { + } else if (width == 8 && (getLong() & 0xffffffff80000000L) != 0) { builder.append('L'); } return builder.toString(); diff --git a/src/main/java/com/reandroid/dex/ins/InsConstWide32.java b/src/main/java/com/reandroid/dex/ins/InsConstWide32.java index 3a640ea0f..f97343809 100644 --- a/src/main/java/com/reandroid/dex/ins/InsConstWide32.java +++ b/src/main/java/com/reandroid/dex/ins/InsConstWide32.java @@ -23,7 +23,7 @@ public InsConstWide32(){ @Override public void set(long value) { - setLong(value); + setData(value); } @Override public long getLong() { @@ -36,7 +36,7 @@ public long getDataAsLong() { } @Override public void setData(long data) { - set(data); + setInteger((int) data); } @Override diff --git a/src/main/java/com/reandroid/dex/key/FieldKey.java b/src/main/java/com/reandroid/dex/key/FieldKey.java index 8c4d9b596..19a6f7d96 100644 --- a/src/main/java/com/reandroid/dex/key/FieldKey.java +++ b/src/main/java/com/reandroid/dex/key/FieldKey.java @@ -15,70 +15,69 @@ */ package com.reandroid.dex.key; -import com.reandroid.dex.id.FieldId; import com.reandroid.dex.smali.SmaliParseException; import com.reandroid.dex.smali.SmaliReader; import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.utils.CompareUtil; -import com.reandroid.utils.StringsUtil; +import com.reandroid.utils.ObjectsUtil; import com.reandroid.utils.collection.CombiningIterator; import com.reandroid.utils.collection.SingleIterator; import java.io.IOException; import java.lang.reflect.Field; import java.util.Iterator; -import java.util.function.Function; - public class FieldKey implements Key { - private final String declaring; - private final String name; - private final String type; + private final TypeKey declaring; + private final StringKey name; + private final TypeKey type; - public FieldKey(String declaring, String name, String type) { + private FieldKey(TypeKey declaring, StringKey name, TypeKey type) { this.declaring = declaring; this.name = name; this.type = type; } - @Deprecated - public FieldKey changeDefining(TypeKey typeKey){ - return changeDeclaring(typeKey); + @Override + public TypeKey getDeclaring() { + return declaring; } - @Deprecated - public FieldKey changeDefining(String defining){ - return changeDeclaring(defining); + public StringKey getNameKey() { + return name; } - public FieldKey changeDeclaring(TypeKey typeKey){ - return changeDeclaring(typeKey.getTypeName()); + public String getName() { + return getNameKey().getString(); } - public FieldKey changeDeclaring(String defining){ - if(defining.equals(getDeclaringName())){ + public TypeKey getType() { + return type; + } + + public FieldKey changeDeclaring(TypeKey typeKey) { + if (typeKey.equals(getDeclaring())) { return this; } - return new FieldKey(defining, getName(), getTypeName()); + return create(typeKey, getNameKey(), getType()); } - public FieldKey changeName(String name){ - if(name.equals(getName())){ + public FieldKey changeName(String name) { + if (name.equals(getName())) { return this; } - return new FieldKey(getDeclaringName(), name, getTypeName()); + return create(getDeclaring(), name, getType()); } - public FieldKey changeType(TypeKey typeKey){ - return changeType(typeKey.getTypeName()); + public FieldKey changeName(StringKey name) { + if (name.equals(getNameKey())) { + return this; + } + return create(getDeclaring(), name, getType()); } - public FieldKey changeType(String type){ - if(type.equals(getTypeName())){ + public FieldKey changeType(TypeKey typeKey) { + if (typeKey.equals(getType())) { return this; } - return new FieldKey(getDeclaringName(), getName(), type); + return create(getDeclaring(), getNameKey(), typeKey); } - @Override - public TypeKey getDeclaring() { - return new TypeKey(getDeclaringName()); - } @Override public Iterator mentionedKeys() { return CombiningIterator.singleThree( @@ -88,244 +87,184 @@ public Iterator mentionedKeys() { SingleIterator.of(getType())); } - public FieldKey replaceTypes(Function function) { - - FieldKey result = this; - - TypeKey typeKey = getDeclaring(); - typeKey = typeKey.changeTypeName(function.apply(typeKey)); - - result = result.changeDeclaring(typeKey); - - typeKey = getType(); - typeKey = typeKey.changeTypeName(function.apply(typeKey)); - - result = result.changeType(typeKey); - - return result; - } @Override - public Key replaceKey(Key search, Key replace) { + public FieldKey replaceKey(Key search, Key replace) { FieldKey result = this; - if(search.equals(result)){ - return replace; + if(search.equals(result)) { + return (FieldKey) replace; } if(search.equals(result.getDeclaring())){ result = result.changeDeclaring((TypeKey) replace); } - if(search.equals(result.getType())){ + if (replace instanceof StringKey && search.equals(result.getNameKey())) { + result = result.changeName((StringKey) replace); + } + if (replace instanceof TypeKey && search.equals(result.getType())) { result = result.changeType((TypeKey) replace); } return result; } - public StringKey getNameKey() { - return new StringKey(getName()); - } - public TypeKey getType() { - return TypeKey.create(getTypeName()); - } - - public String getDeclaringName() { - return declaring; - } - public String getName() { - return name; - } - public String getTypeName() { - return type; - } - @Override public void append(SmaliWriter writer) throws IOException { - writer.appendOptional(getDeclaring()); - writer.append("->"); - writer.append(getName()); + getDeclaring().append(writer); + writer.append('-'); + writer.append('>'); + getNameKey().appendSimpleName(writer); writer.append(':'); - writer.appendOptional(getType()); + getType().append(writer); } @Override public int compareTo(Object obj) { - return compareTo(obj, true); - } - public int compareTo(Object obj, boolean compareDefining) { - if(obj == null){ + if (obj == null) { return -1; } FieldKey key = (FieldKey) obj; - int i; - if(compareDefining){ - i = CompareUtil.compare(getDeclaringName(), key.getDeclaringName()); - if(i != 0) { - return i; - } - } - i = CompareUtil.compare(getName(), key.getName()); + int i = CompareUtil.compare(getDeclaring(), key.getDeclaring()); if(i != 0) { return i; } - return CompareUtil.compare(getTypeName(), key.getTypeName()); - } - - @Override - public int hashCode() { - int hash = 1; - String defining = getDeclaringName(); - if(defining != null){ - hash += defining.hashCode(); + i = CompareUtil.compare(getNameKey(), key.getNameKey()); + if (i != 0) { + return i; } - return hash * 31 + getName().hashCode(); + return CompareUtil.compare(getType(), key.getType()); } - public boolean equalsDeclaring(String declaring){ + public boolean equalsDeclaring(TypeKey declaring) { if(declaring == null){ return false; } - return KeyUtil.matches(getDeclaringName(), declaring); + return getDeclaring().equals(declaring); } - public boolean equalsDeclaring(TypeKey declaring){ - if(declaring == null){ + public boolean equalsDeclaring(FieldKey other) { + if (other == null) { return false; } - return KeyUtil.matches(getDeclaringName(), declaring.getTypeName()); + if (other == this) { + return true; + } + return getDeclaring().equals(other.getDeclaring()); } - public boolean equalsDeclaring(FieldKey other){ - if(other == null){ + public boolean equalsIgnoreDeclaring(FieldKey other) { + if( other == null) { return false; } - if(other == this){ + if (other == this) { return true; } - return KeyUtil.matches(getDeclaringName(), other.getDeclaringName()); + return getName().equals(other.getName()) && + getType().equals(other.getType()); } public boolean equalsIgnoreName(FieldKey other){ - if(other == null){ + if( other == null) { return false; } - if(other == this){ + if (other == this) { return true; } - if(!KeyUtil.matches(getDeclaringName(), other.getDeclaringName())){ - return false; - } - return KeyUtil.matches(getTypeName(), other.getTypeName()); + return getDeclaring().equals(other.getDeclaring()) && + getType().equals(other.getType()); } - public boolean equalsName(FieldKey other){ - if(other == null){ + public boolean equalsName(FieldKey other) { + if (other == null) { return false; } - if(other == this){ + if (other == this) { return true; } - return KeyUtil.matches(getName(), other.getName()); - } - public boolean equalsName(String name){ - return KeyUtil.matches(getName(), name); + return getNameKey().equals(other.getNameKey()); } - public boolean equalsType(String returnTypeName){ - return KeyUtil.matches(getTypeName(), returnTypeName); + public boolean equalsName(String name) { + return ObjectsUtil.equals(getName(), name); } - public boolean equalsType(TypeKey returnType){ - if(returnType == null){ + public boolean equalsType(TypeKey typeKey) { + if (typeKey == null) { return false; } - return KeyUtil.matches(getTypeName(), returnType.getTypeName()); + return getType().equals(typeKey); } - public boolean equalsType(FieldKey other){ - if(other == null){ + public boolean equalsType(FieldKey other) { + if (other == null) { return false; } - if(other == this){ + if (other == this) { return true; } - return KeyUtil.matches(getTypeName(), other.getTypeName()); + return getType().equals(other.getType()); } @Override public boolean equals(Object obj) { - return equals(obj, true, true); - } - public boolean equals(Object obj, boolean checkDefining, boolean checkType) { - if (this == obj) { + if (obj == this) { return true; } if (!(obj instanceof FieldKey)) { return false; } - FieldKey fieldKey = (FieldKey) obj; - if(!KeyUtil.matches(getName(), fieldKey.getName())){ - return false; - } - if(checkDefining){ - if(!KeyUtil.matches(getDeclaringName(), fieldKey.getDeclaringName())){ - return false; - } - } - if(checkType){ - return KeyUtil.matches(getTypeName(), fieldKey.getTypeName()); - } - return true; + FieldKey other = (FieldKey) obj; + return getDeclaring().equals(other.getDeclaring()) && + getNameKey().equals(other.getNameKey()) && + getType().equals(other.getType()); + } + @Override + public int hashCode() { + return ObjectsUtil.hash(getDeclaring(), getNameKey(), getType()); } @Override public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(getDeclaringName()); - builder.append("->"); - builder.append(getName()); - String type = getTypeName(); - if(type != null){ - builder.append(':'); - builder.append(getTypeName()); + return getDeclaring() + "->" + getNameKey().getAsSimpleName() + ':' + getType(); + } + + + public static FieldKey create(TypeKey declaring, StringKey name, TypeKey type) { + if (declaring == null || name == null || type == null) { + return null; } - return builder.toString(); + return new FieldKey(declaring, name, type); + } + public static FieldKey create(TypeKey declaring, String name, TypeKey type) { + return create(declaring, StringKey.create(name), type); } public static FieldKey parse(String text) { - if(text == null){ + return parse(text, 0); + } + + public static FieldKey parse(String text, int start) { + if (start + 6 >= text.length() || text.charAt(start) != 'L') { return null; } - text = text.trim(); - if(text.length() < 6 || text.charAt(0) != 'L'){ + + int i = text.indexOf("->", start); + if (i < 0) { return null; } - int i = text.indexOf(";->"); - if(i < 0){ + + TypeKey declaring = TypeKey.parseBinaryType(text, start, i); + if (declaring == null) { return null; } - String defining = text.substring(0, i + 1); - text = text.substring(i + 3); - i = text.indexOf(':'); - if(i < 0){ + start = start + declaring.getTypeName().length() + 2; + i = text.indexOf(':', start); + + if (i < 0 || i == start) { return null; } - String name = text.substring(0, i); - text = text.substring(i + 1); - String type = null; - if(!StringsUtil.isEmpty(text)){ - type = text; - } - return new FieldKey(defining, name, type); + + String name = text.substring(start, i); + start = start + name.length() + 1; + i = text.length() - start; + + TypeKey type = TypeKey.parseBinaryType(text, start, i); + + return create(declaring, name, type); } public static FieldKey convert(Field field) { TypeKey declaring = TypeKey.convert(field.getDeclaringClass()); TypeKey type = TypeKey.convert(field.getType()); - return new FieldKey(declaring.getTypeName(), field.getName(), type.getTypeName()); - } - public static FieldKey create(FieldId fieldId){ - TypeKey defining = fieldId.getDefining(); - if(defining == null){ - return null; - } - String name = fieldId.getName(); - if(name == null) { - return null; - } - TypeKey fieldType = fieldId.getFieldType(); - if(fieldType == null){ - return null; - } - return new FieldKey(defining.getTypeName(), name, fieldType.getTypeName()); + return create(declaring, field.getName(), type); } public static FieldKey read(SmaliReader reader) throws IOException { @@ -333,24 +272,9 @@ public static FieldKey read(SmaliReader reader) throws IOException { reader.skipWhitespacesOrComment(); SmaliParseException.expect(reader, '-'); SmaliParseException.expect(reader, '>'); - reader.skipWhitespacesOrComment(); - int i; - int i1 = reader.indexOfBeforeLineEnd(':'); - int i2 = reader.indexOfWhiteSpaceOrComment(); - if(i1 < 0 && i2 < 0){ - throw new SmaliParseException("Expecting ':'", reader); - } - if(i1 < 0 || i2 >= 0 && i2 < i1){ - i = i2; - }else { - i = i1; - } - char stop = reader.getASCII(i); - String name = reader.readEscapedString(stop); - reader.skipWhitespacesOrComment(); - SmaliParseException.expect(reader, ':'); + StringKey name = StringKey.readSimpleName(reader, ':'); + reader.skip(1); TypeKey type = TypeKey.read(reader); - return new FieldKey(declaring.getTypeName(), name, type.getTypeName()); + return create(declaring, name, type); } - } diff --git a/src/main/java/com/reandroid/dex/key/MethodKey.java b/src/main/java/com/reandroid/dex/key/MethodKey.java index c02674acf..be7d1f0d1 100644 --- a/src/main/java/com/reandroid/dex/key/MethodKey.java +++ b/src/main/java/com/reandroid/dex/key/MethodKey.java @@ -163,13 +163,28 @@ public MethodKey replaceKey(Key search, Key replace) { public void append(SmaliWriter writer) throws IOException { getDeclaring().append(writer); writer.append("->"); - writer.append(getName()); + getNameKey().appendSimpleName(writer); getProto().append(writer); } @Override public int compareTo(Object obj) { - return compareTo(obj, true); + if (obj == this) { + return 0; + } + if (obj == null) { + return -1; + } + MethodKey key = (MethodKey) obj; + int i = CompareUtil.compare(getDeclaring(), key.getDeclaring()); + if (i != 0) { + return i; + } + i = CompareUtil.compare(getNameKey(), key.getNameKey()); + if(i != 0) { + return i; + } + return CompareUtil.compare(getProto(), key.getProto()); } public int compareTo(Object obj, boolean checkDefining) { if (obj == null) { @@ -287,10 +302,6 @@ public boolean equalsReturnType(MethodKey other){ } return getProto().equalsReturnType(other.getProto()); } - @Override - public boolean equals(Object obj) { - return equals(obj, true, true); - } public boolean equals(Object obj, boolean checkDefining, boolean checkType) { if (this == obj) { return true; @@ -299,7 +310,7 @@ public boolean equals(Object obj, boolean checkDefining, boolean checkType) { return false; } MethodKey methodKey = (MethodKey) obj; - if(!KeyUtil.matches(getName(), methodKey.getName())){ + if(!ObjectsUtil.equals(getNameKey(), methodKey.getNameKey())){ return false; } if(!TypeListKey.equalsIgnoreEmpty(getParameters(), methodKey.getParameters())) { @@ -316,14 +327,26 @@ public boolean equals(Object obj, boolean checkDefining, boolean checkType) { return true; } - + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof MethodKey)) { + return false; + } + MethodKey methodKey = (MethodKey) obj; + return ObjectsUtil.equals(getNameKey(), methodKey.getNameKey()) && + ObjectsUtil.equals(getDeclaring(), methodKey.getDeclaring()) && + ObjectsUtil.equals(getProto(), methodKey.getProto()); + } @Override public int hashCode() { return ObjectsUtil.hash(getDeclaring(), getNameKey(), getProto()); } @Override public String toString() { - return getDeclaring() + "->" + getName() + getProto(); + return getDeclaring() + "->" + getNameKey().getAsSimpleName() + getProto(); } public static MethodKey parse(String text) { @@ -388,7 +411,7 @@ public static MethodKey read(SmaliReader reader) throws IOException { SmaliParseException.expect(reader, '-'); SmaliParseException.expect(reader, '>'); reader.skipWhitespacesOrComment(); - StringKey name = StringKey.create(reader.readEscapedString('(')); + StringKey name = StringKey.readSimpleName(reader, '('); ProtoKey protoKey = ProtoKey.read(reader); return create(declaring, name, protoKey); } diff --git a/src/main/java/com/reandroid/dex/key/PrimitiveKey.java b/src/main/java/com/reandroid/dex/key/PrimitiveKey.java index d0ba7eae7..29ebf7007 100644 --- a/src/main/java/com/reandroid/dex/key/PrimitiveKey.java +++ b/src/main/java/com/reandroid/dex/key/PrimitiveKey.java @@ -1,6 +1,22 @@ +/* + * 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 com.reandroid.dex.common.DexUtils; +import com.reandroid.dex.smali.SmaliReader; import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.utils.CompareUtil; import com.reandroid.utils.HexUtil; @@ -19,7 +35,7 @@ public PrimitiveKey() { public abstract Object getValue(); public abstract TypeKey valueType(); public abstract int width(); - public abstract long asLongValue(); + public abstract long getValueAsLong(); public boolean isNumber() { return false; } public boolean isBoolean() { return false; } @@ -64,6 +80,12 @@ public static PrimitiveKey of(boolean value) { public static PrimitiveKey of(short value) { return new ShortKey(value); } public static PrimitiveKey of(int width, long value) { return new NumberXKey(width, value); } + public static PrimitiveKey parse(String text) { + return PrimitiveKeyHelper.parse(text); + } + public static PrimitiveKey readSafe(SmaliReader reader) { + return PrimitiveKeyHelper.readSafe(reader); + } public static abstract class NumberKey extends PrimitiveKey { public NumberKey() { @@ -110,8 +132,8 @@ public int width() { return 0; } @Override - public long asLongValue() { - return value() ? -1 : 0; + public long getValueAsLong() { + return value() ? 1 : 0; } @Override @@ -174,7 +196,7 @@ public int width() { return 1; } @Override - public long asLongValue() { + public long getValueAsLong() { return value(); } @@ -245,7 +267,7 @@ public int width() { return 0; } @Override - public long asLongValue() { + public long getValueAsLong() { return value(); } @@ -316,7 +338,7 @@ public int width() { return 8; } @Override - public long asLongValue() { + public long getValueAsLong() { return Double.doubleToLongBits(value()); } @Override @@ -386,7 +408,7 @@ public int width() { return 4; } @Override - public long asLongValue() { + public long getValueAsLong() { return Float.floatToIntBits(value()); } @@ -458,7 +480,7 @@ public int width() { return 4; } @Override - public long asLongValue() { + public long getValueAsLong() { return value(); } @@ -497,6 +519,11 @@ public boolean equals(Object obj) { public void append(SmaliWriter writer) throws IOException { writer.appendHex(value()); } + + @Override + public String toString() { + return HexUtil.toSignedHex(getValue()); + } } public static class LongKey extends NumberKey { @@ -521,7 +548,7 @@ public int width() { return 8; } @Override - public long asLongValue() { + public long getValueAsLong() { return value(); } @@ -563,6 +590,10 @@ public boolean equals(Object obj) { public void append(SmaliWriter writer) throws IOException { writer.appendHex(value()); } + @Override + public String toString() { + return HexUtil.toSignedHex(getValue()); + } } public static class ShortKey extends NumberKey { @@ -587,7 +618,7 @@ public int width() { return 2; } @Override - public long asLongValue() { + public long getValueAsLong() { return value(); } @@ -658,7 +689,7 @@ public int width() { return width; } @Override - public long asLongValue() { + public long getValueAsLong() { return value(); } @Override diff --git a/src/main/java/com/reandroid/dex/key/PrimitiveKeyHelper.java b/src/main/java/com/reandroid/dex/key/PrimitiveKeyHelper.java new file mode 100644 index 000000000..c920e7d88 --- /dev/null +++ b/src/main/java/com/reandroid/dex/key/PrimitiveKeyHelper.java @@ -0,0 +1,292 @@ +/* + * 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 com.reandroid.dex.smali.SmaliReader; +import com.reandroid.utils.HexUtil; + +class PrimitiveKeyHelper { + + public static PrimitiveKey parse(String text) { + if (text == null || text.length() == 0) { + return null; + } + char first = text.charAt(0); + if (isNumbersPrefix(first)) { + return parseNumbers(text); + } + if (first == '\'') { + return parseChar(text); + } + if (first == 't' || first == 'f') { + return parseBoolean(text); + } + return null; + } + public static PrimitiveKey readSafe(SmaliReader reader) { + if (reader.finished()) { + return null; + } + int position = reader.position(); + char first = reader.getASCII(position); + if (isNumbersPrefix(first)) { + return readNumbers(reader); + } + if (first == '\'') { + return readChar(reader); + } + if (first == 't' || first == 'f') { + return readBoolean(reader); + } + reader.position(position); + return null; + } + private static PrimitiveKey readChar(SmaliReader reader) { + int position = reader.position(); + if (reader.read() != '\'') { + reader.position(position); + return null; + } + char ch = reader.readASCII(); + if(ch == '\\'){ + ch = reader.readASCII(); + if (ch == 'u') { + try{ + int i = HexUtil.parseHex(reader.readString(4)); + ch = (char) i; + } catch (NumberFormatException ex) { + reader.position(position); + return null; + } + } else { + if (ch == 'b') { + ch = '\b'; + } else if (ch == 'f') { + ch = '\f'; + } else if (ch == 'n') { + ch = '\n'; + } else if (ch == 'r') { + ch = '\r'; + } else if (ch == 't') { + ch = '\t'; + } else { + reader.position(position); + return null; + } + } + } + if (reader.read() != '\'') { + reader.position(position); + return null; + } + return PrimitiveKey.of(ch); + } + private static PrimitiveKey parseChar(String text) { + if (text.length() < 3) { + return null; + } + if (text.charAt(0) != '\'') { + return null; + } + int last = text.length() - 1; + if (text.charAt(last) != '\'') { + return null; + } + text = text.substring(1, last); + char c = text.charAt(0); + if (text.length() == 1) { + return PrimitiveKey.of(c); + } + if (c != '\\') { + return null; + } + c = text.charAt(1); + + if (c == 'u') { + if (text.length() == 6) { + try { + return PrimitiveKey.of((char) HexUtil.parseHex(text.substring(2))); + } catch (NumberFormatException ignored) { + } + } + } else if (text.length() == 2){ + if (c == 'b') { + c = '\b'; + } else if (c == 'f') { + c = '\f'; + } else if (c == 'n') { + c = '\n'; + } else if (c == 'r') { + c = '\r'; + } else if (c == 't') { + c = '\t'; + } else { + return null; + } + return PrimitiveKey.of(c); + } + return null; + } + private static PrimitiveKey readBoolean(SmaliReader reader) { + int position = reader.position(); + char first = reader.readASCII(); + if (first == 't') { + if (reader.read() == 'r' && + reader.read() == 'u' && + reader.read() == 'e') { + return PrimitiveKey.of(true); + } + } else if (first == 'f') { + if (reader.read() == 'a' && + reader.read() == 'l' && + reader.read() == 's' && + reader.read() == 'e') { + return PrimitiveKey.of(false); + } + } + reader.position(position); + return null; + } + private static PrimitiveKey parseBoolean(String text) { + if (text.equals("true")) { + return PrimitiveKey.of(true); + } + if (text.equals("false")) { + return PrimitiveKey.of(false); + } + return null; + } + private static PrimitiveKey readNumbers(SmaliReader reader) { + int position = reader.position(); + char first = reader.readASCII(); + if (first == '-' || first == '+') { + first = reader.readASCII(); + } + char x = 0; + if (!reader.finished()) { + x = reader.readASCII(); + } + reader.position(position); + String number = reader.readStringForNumber(); + if (first == '0' && x == 'x') { + try { + return readHex(number); + } catch (NumberFormatException ignored) { + reader.position(position); + return null; + } + } + if (number.charAt(0) == '+') { + number = number.substring(1); + } + if (isFloatOrDouble(number)) { + try { + return parseFloatOrDouble(number); + } catch (NumberFormatException ignored) { + } + } else { + try { + return parsePlainNumber(number); + } catch (NumberFormatException ignored) { + } + } + reader.position(position); + return null; + } + + private static PrimitiveKey parseNumbers(String text) { + int position = 0; + char first = text.charAt(position); + int length = text.length(); + if (length > 1 && (first == '-' || first == '+')) { + first = text.charAt(1); + position ++; + } + char x = 0; + if (length > position + 1) { + x = text.charAt(position + 1); + } + String number = text; + if (first == '0' && x == 'x') { + try { + return readHex(text); + } catch (NumberFormatException ignored) { + return null; + } + } + if (number.charAt(0) == '+') { + number = number.substring(1); + } + if (isFloatOrDouble(number)) { + try { + return parseFloatOrDouble(number); + } catch (NumberFormatException ignored) { + } + } else { + try { + return parsePlainNumber(number); + } catch (NumberFormatException ignored) { + } + } + return null; + } + + private static PrimitiveKey parsePlainNumber(String number) { + char suffix = number.charAt(number.length() - 1); + if (suffix == 'L' || suffix == 'l') { + number = number.substring(0, number.length() - 1); + return PrimitiveKey.of(Long.parseLong(number)); + } + return PrimitiveKey.of(Integer.parseInt(number)); + } + private static PrimitiveKey parseFloatOrDouble(String number) { + int lastIndex = number.length() - 1; + if (number.charAt(lastIndex) == 'f') { + number = number.substring(0, lastIndex); + return PrimitiveKey.of(Float.parseFloat(number)); + } + return PrimitiveKey.of(Double.parseDouble(number)); + } + private static boolean isFloatOrDouble(String number) { + if (number.indexOf('.') >= 0) { + return true; + } + return number.contains("NaN") || + number.contains("Infinity"); + } + private static PrimitiveKey readHex(String hex) { + char suffix = hex.charAt(hex.length() - 1); + if (suffix == 'L') { + return PrimitiveKey.of(HexUtil.parseHexLong(hex)); + } + if (suffix == 'S' || suffix == 's') { + return PrimitiveKey.of(HexUtil.parseHexShort(hex)); + } + if (suffix == 't') { + return PrimitiveKey.of(HexUtil.parseHexByte(hex)); + } + return PrimitiveKey.of(HexUtil.parseHexInteger(hex)); + } + private static boolean isNumbersPrefix(char c) { + if (c >= '0' && c <= '9') { + return true; + } + return c == '-' || + c == '+' || + c == 'N' || + c == 'I'; + } +} diff --git a/src/main/java/com/reandroid/dex/key/ProtoKey.java b/src/main/java/com/reandroid/dex/key/ProtoKey.java index 693e07cff..72a554fb6 100644 --- a/src/main/java/com/reandroid/dex/key/ProtoKey.java +++ b/src/main/java/com/reandroid/dex/key/ProtoKey.java @@ -144,15 +144,18 @@ public void append(SmaliWriter writer) throws IOException { @Override public int compareTo(Object obj) { - if(obj == null){ + if (obj == null) { return -1; } + if (obj == this) { + return 0; + } ProtoKey key = (ProtoKey) obj; - int i = CompareUtil.compare(getParameters(), key.getParameters()); + int i = CompareUtil.compare(getReturnType(), key.getReturnType()); if(i != 0) { return i; } - return CompareUtil.compare(getReturnType(), key.getReturnType()); + return CompareUtil.compare(getParameters(), key.getParameters()); } public boolean equalsReturnType(TypeKey returnType) { @@ -189,7 +192,7 @@ public boolean equals(Object obj) { } ProtoKey protoKey = (ProtoKey) obj; return ObjectsUtil.equals(getReturnType(), protoKey.getReturnType()) && - TypeListKey.equalsIgnoreEmpty(getParameters(), protoKey.getParameters()); + ObjectsUtil.equals(getParameters(), protoKey.getParameters()); } @Override @@ -221,21 +224,7 @@ public static ProtoKey parse(String text) { if (text == null) { return null; } - text = text.trim(); - if (text.length() < 3 || text.charAt(0) != '(') { - return null; - } - text = text.substring(1); - int i = text.indexOf(')'); - if (i < 0) { - return null; - } - TypeListKey parameters = TypeListKey.parseParameters(text.substring(0, i).trim()); - String returnType = text.substring(i + 1).trim(); - if (StringsUtil.isEmpty(returnType)) { - return null; - } - return new ProtoKey(parameters, TypeKey.create(returnType)); + return parse(text, 0); } public static ProtoKey parse(String text, int start) { if (text.length() - start < 3 || text.charAt(start) != '(') { diff --git a/src/main/java/com/reandroid/dex/key/StringKey.java b/src/main/java/com/reandroid/dex/key/StringKey.java index 8087d4042..57bb0f412 100644 --- a/src/main/java/com/reandroid/dex/key/StringKey.java +++ b/src/main/java/com/reandroid/dex/key/StringKey.java @@ -20,6 +20,7 @@ import com.reandroid.dex.smali.SmaliReader; import com.reandroid.dex.smali.SmaliWriter; import com.reandroid.utils.CompareUtil; +import com.reandroid.utils.HexUtil; import com.reandroid.utils.ObjectsUtil; import com.reandroid.utils.StringsUtil; import com.reandroid.utils.collection.CombiningIterator; @@ -27,7 +28,6 @@ import java.io.IOException; import java.util.Iterator; -import java.util.Objects; public class StringKey implements Key{ @@ -47,6 +47,9 @@ public String getEncodedString() { public String getQuoted() { return DexUtils.quoteString(getString()); } + public String getAsSimpleName() { + return encodeSimpleName(getString()); + } @Override public boolean isPlatform() { @@ -92,6 +95,10 @@ public void append(SmaliWriter writer, boolean enableComment) throws IOException DexUtils.appendCommentString(250, writer.getCommentAppender(), getString()); } } + public void appendSimpleName(SmaliWriter writer) throws IOException { + writer.append(getAsSimpleName()); + } + @Override public int compareTo(Object obj) { if(obj == null){ @@ -157,5 +164,162 @@ public static StringKey read(SmaliReader reader) throws IOException{ return create(str); } + public static String encodeSimpleName(String name) { + StringBuilder builder = null; + int length = name.length(); + for (int i = 0; i < length; i++) { + char c = name.charAt(i); + String encoded = encodeSimpleName(c); + if (encoded != null) { + if (builder == null) { + builder = new StringBuilder(); + builder.append(name, 0, i); + } + builder.append(encoded); + } else if (builder != null) { + builder.append(c); + } + } + if (builder == null) { + return name; + } + return builder.toString(); + } + private static String encodeSimpleName(char c) { + String encoded; + if (c == ' ') { + encoded = HexUtil.toHex( "\\u", c, 4); + } else if (c == '\n') { + encoded = "\\n"; + } else if (c == '\r') { + encoded = "\\r"; + } else if (c == '\t') { + encoded = "\\t"; + } else if (c == '\b') { + encoded = "\\b"; + } else if (c == '\f') { + encoded = "\\f"; + } else { + encoded = null; + } + return encoded; + } + + public static String decodeEscapedString(String encoded) { + return decodeEscapedString(encoded, 0); + } + public static String decodeEscapedString(String encoded, int start) { + StringBuilder builder = null; + int length = encoded.length(); + boolean escaped = false; + for (int i = start; i < length; i++) { + char c = encoded.charAt(i); + if (escaped) { + if (builder == null) { + builder = new StringBuilder(); + builder.append(encoded, start, i - 1); + } + if (c == 'u') { + Character hex = decodeNextHex(encoded, i + 1); + if (hex != null) { + builder.append(hex.charValue()); + i = i + 4; + } else { + builder.append(c); + } + } else { + builder.append(getEscaped(c)); + } + escaped = false; + } else if (c == '\\') { + escaped = true; + } else if (builder != null) { + builder.append(c); + } + } + if (builder == null) { + return encoded; + } + return builder.toString(); + } + private static char getEscaped(char c) { + if (c == 'n') { + return '\n'; + } + if (c == 'b') { + return '\b'; + } + if (c == 'f') { + return '\f'; + } + if (c == 'r') { + return '\r'; + } + if (c == 't') { + return '\t'; + } + return c; + } + private static Character decodeNextHex(String text, int start) { + int length = text.length(); + int end = start + 4; + if (end > length) { + return null; + } + int value = 0; + for (int i = start; i < end; i++) { + int v = HexUtil.decodeHexChar(text.charAt(i)); + if (v == -1) { + return null; + } + value = value << 4; + value = value | v; + } + return (char) value; + } + public static StringKey readSimpleName(SmaliReader reader, char stopChar) throws IOException { + int position = reader.position(); + String name = reader.readEscapedString(stopChar); + SmaliParseException.expect(reader, stopChar); + reader.skip(-1); + String error = validateSimpleName(name); + if (error != null) { + reader.position(position); + throw new SmaliParseException(error, reader); + } + return create(name); + } + + private static String validateSimpleName(String name) { + int length = name.length(); + if (length == 0) { + return "Invalid name"; + } + for (int i = 0; i < length; i++) { + char c = name.charAt(i); + if (isInvalidSimpleName(c)) { + return "Invalid name character '" + c + "'"; + } + } + return null; + } + private static boolean isInvalidSimpleName(char c) { + return c == '(' || + c == ')' || + c == '[' || + c == ']' || + c == '{' || + c == '}' || + c == ';' || + c == '/' || + c == '\\' || + c == ':' || + c == '.' || + c == '*' || + c == '%' || + c == '|' || + c == '^'; + } + public static final StringKey EMPTY = new StringKey(StringsUtil.EMPTY); } diff --git a/src/main/java/com/reandroid/dex/model/DexClass.java b/src/main/java/com/reandroid/dex/model/DexClass.java index 4548c79ec..3aca3c675 100644 --- a/src/main/java/com/reandroid/dex/model/DexClass.java +++ b/src/main/java/com/reandroid/dex/model/DexClass.java @@ -145,9 +145,9 @@ public DexField getField(FieldKey fieldKey) { } public DexField getDeclaredField(FieldKey fieldKey) { Iterator iterator = getDeclaredFields(); - while (iterator.hasNext()){ + while (iterator.hasNext()) { DexField dexField = iterator.next(); - if(fieldKey.equals(dexField.getKey(), false, true)){ + if (fieldKey.equalsIgnoreDeclaring(dexField.getKey())) { return dexField; } } diff --git a/src/main/java/com/reandroid/dex/model/RClass.java b/src/main/java/com/reandroid/dex/model/RClass.java index c0bad9b92..d50013e3d 100644 --- a/src/main/java/com/reandroid/dex/model/RClass.java +++ b/src/main/java/com/reandroid/dex/model/RClass.java @@ -47,7 +47,7 @@ public RField load(ResourceEntry resourceEntry){ return null; } String name = RField.sanitizeResourceName(resourceEntry.getName()); - FieldKey fieldKey = new FieldKey(getKey().getTypeName(), name, TypeKey.TYPE_I.getTypeName()); + FieldKey fieldKey = FieldKey.create(getKey(), name, TypeKey.TYPE_I); RField rField = getOrCreateStaticField(fieldKey); rField.setResourceId(resourceEntry.getResourceId()); return rField; diff --git a/src/main/java/com/reandroid/dex/smali/SmaliReader.java b/src/main/java/com/reandroid/dex/smali/SmaliReader.java index ff52b202a..c0d1c54a7 100644 --- a/src/main/java/com/reandroid/dex/smali/SmaliReader.java +++ b/src/main/java/com/reandroid/dex/smali/SmaliReader.java @@ -438,7 +438,7 @@ private static boolean isNumber(byte b){ if(b >= 'a' && b <= 'z'){ return true; } - if(b >= 'A' && b <= 'z'){ + if(b >= 'A' && b <= 'Z'){ return true; } switch (b){ diff --git a/src/main/java/com/reandroid/dex/smali/SmaliWriter.java b/src/main/java/com/reandroid/dex/smali/SmaliWriter.java index e0ee464a7..c0711b7bf 100644 --- a/src/main/java/com/reandroid/dex/smali/SmaliWriter.java +++ b/src/main/java/com/reandroid/dex/smali/SmaliWriter.java @@ -200,7 +200,7 @@ public void appendHex(int width, long l) throws IOException { append('t'); } else if (width == 2) { append('S'); - } else if (width == 8 && hex.length() > 10) { + } else if (width == 8 && (l & 0xffffffff80000000L) != 0) { append('L'); } appendResourceIdComment(l); 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 7ebf81c9d..d2dac174e 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliDef.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliDef.java @@ -18,10 +18,7 @@ import com.reandroid.dex.common.AccessFlag; import com.reandroid.dex.common.HiddenApiFlag; import com.reandroid.dex.common.Modifier; -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.smali.SmaliDirective; import com.reandroid.dex.smali.SmaliReader; import com.reandroid.dex.smali.SmaliRegion; @@ -34,7 +31,7 @@ public abstract class SmaliDef extends Smali implements SmaliRegion { - private String name; + private StringKey name; private AccessFlag[] accessFlags; private SmaliAnnotationSet annotation; @@ -76,12 +73,22 @@ public void setHiddenApiFlags(HiddenApiFlag[] hiddenApiFlags) { this.hiddenApiFlags = hiddenApiFlags; } - public String getName() { + public StringKey getNameKey() { return name; } - public void setName(String name) { + public String getName() { + StringKey name = getNameKey(); + if (name != null) { + return name.getString(); + } + return null; + } + public void setName(StringKey name) { this.name = name; } + public void setName(String name) { + setName(StringKey.create(name)); + } public TypeKey getDefining() { TypeKey typeKey = null; SmaliDefSet defSet = getDefSet(); 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 14193975a..a2c9335e3 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliField.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliField.java @@ -20,6 +20,7 @@ import com.reandroid.dex.common.Modifier; import com.reandroid.dex.key.FieldKey; import com.reandroid.dex.key.Key; +import com.reandroid.dex.key.StringKey; import com.reandroid.dex.key.TypeKey; import com.reandroid.dex.smali.SmaliDirective; import com.reandroid.dex.smali.SmaliParseException; @@ -48,19 +49,12 @@ public FieldKey getKey(){ } public void setKey(Key key) { FieldKey fieldKey = (FieldKey) key; - setName(fieldKey.getName()); + setName(fieldKey.getNameKey()); setType(fieldKey.getType()); setDefining(fieldKey.getDeclaring()); } - public FieldKey getKey(TypeKey declaring){ - TypeKey type = getType(); - if(type == null){ - return null; - } - return new FieldKey( - declaring.getTypeName(), - getName(), - type.getTypeName()); + public FieldKey getKey(TypeKey declaring) { + return FieldKey.create(declaring, getName(), getType()); } public TypeKey getType() { @@ -148,21 +142,16 @@ public void append(SmaliWriter writer) throws IOException { } @Override - public void parse(SmaliReader reader) throws IOException{ + public void parse(SmaliReader reader) throws IOException { SmaliParseException.expect(reader, getSmaliDirective()); setAccessFlags(AccessFlag.parse(reader)); setHiddenApiFlags(HiddenApiFlag.parse(reader)); - parseName(reader); + setName(StringKey.readSimpleName(reader, ':')); + reader.skip(1); setType(TypeKey.read(reader)); parseValue(reader); parseAnnotationSet(reader); } - private void parseName(SmaliReader reader) { - reader.skipWhitespaces(); - int length = reader.indexOf(':') - reader.position(); - setName(reader.readString(length)); - reader.skip(1); // : - } private void parseValue(SmaliReader reader) throws IOException { reader.skipWhitespaces(); if(reader.finished()) { diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliInstruction.java b/src/main/java/com/reandroid/dex/smali/model/SmaliInstruction.java index c5695b61e..6c67dd293 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliInstruction.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliInstruction.java @@ -78,10 +78,10 @@ public boolean hasNumberData() { public long getDataAsLong() { SmaliInstructionOperand operand = getOperand(); if(operand instanceof SmaliInstructionOperand.SmaliHexOperand){ - return operand.asLongValue(); + return operand.getValueAsLong(); } if(operand instanceof SmaliInstructionOperand.SmaliLabelOperand){ - return operand.getIntegerData() - getAddress(); + return ((int)operand.getValueAsLong()) - getAddress(); } return 0; } diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliInstructionOperand.java b/src/main/java/com/reandroid/dex/smali/model/SmaliInstructionOperand.java index 0f54cc263..fb465414f 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliInstructionOperand.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliInstructionOperand.java @@ -32,8 +32,7 @@ public SmaliInstructionOperand(){ super(); } - public abstract int getIntegerData(); - public abstract long asLongValue(); + public abstract long getValueAsLong(); public abstract OperandType getOperandType(); @Override public abstract void append(SmaliWriter writer) throws IOException; @@ -59,11 +58,7 @@ public SmaliLabel getLabel() { } @Override - public int getIntegerData() { - return getLabel().getIntegerData(); - } - @Override - public long asLongValue() { + public long getValueAsLong() { return getLabel().getIntegerData(); } @@ -91,9 +86,6 @@ public SmaliHexOperand(){ valueNumber = new SmaliValueInteger(); } - public Number getNumber() { - return valueNumber.getNumber(); - } public void setNumber(Number number) { setNumberValue(SmaliValueNumber.createFor(number)); } @@ -109,22 +101,8 @@ public void setNumberValue(SmaliValueNumber valueNumber) { } @Override - public int getIntegerData() { - SmaliValueNumber valueNumber = getValueNumber(); - if (valueNumber instanceof SmaliValueInteger) { - return ((SmaliValueInteger) valueNumber).getValue(); - } - if (valueNumber instanceof SmaliValueShort) { - return ((SmaliValueShort) valueNumber).getValue(); - } - if (valueNumber instanceof SmaliValueByte) { - return ((SmaliValueByte) valueNumber).getValue(); - } - return valueNumber.unsignedInt(); - } - @Override - public long asLongValue() { - return getValueNumber().asLongValue(); + public long getValueAsLong() { + return getValueNumber().getValueAsLong(); } @Override @@ -175,12 +153,7 @@ public void setNumber(int number) { } @Override - public int getIntegerData() { - return getNumber(); - } - - @Override - public long asLongValue() { + public long getValueAsLong() { return number; } @Override @@ -230,11 +203,7 @@ public void setKey(Key key) { } @Override - public int getIntegerData() { - return -1; - } - @Override - public long asLongValue() { + public long getValueAsLong() { return -1; } @@ -351,11 +320,7 @@ public int hashCode() { public static final SmaliInstructionOperand NO_OPERAND = new SmaliInstructionOperand() { @Override - public int getIntegerData() { - return -1; - } - @Override - public long asLongValue() { + public long getValueAsLong() { return -1; } 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 2c4661329..07faf254f 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliMethod.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliMethod.java @@ -19,10 +19,7 @@ import com.reandroid.dex.common.HiddenApiFlag; import com.reandroid.dex.common.Modifier; import com.reandroid.dex.common.RegistersTable; -import com.reandroid.dex.key.Key; -import com.reandroid.dex.key.MethodKey; -import com.reandroid.dex.key.ProtoKey; -import com.reandroid.dex.key.TypeKey; +import com.reandroid.dex.key.*; import com.reandroid.dex.smali.SmaliDirective; import com.reandroid.dex.smali.SmaliParseException; import com.reandroid.dex.smali.SmaliReader; @@ -63,7 +60,7 @@ public MethodKey getKey(){ } public void setKey(Key key) { MethodKey methodKey = (MethodKey) key; - setName(methodKey.getName()); + setName(methodKey.getNameKey()); setProtoKey(methodKey.getProto()); setDefining(methodKey.getDeclaring()); } @@ -150,7 +147,7 @@ public void parse(SmaliReader reader) throws IOException { SmaliParseException.expect(reader, getSmaliDirective()); setAccessFlags(AccessFlag.parse(reader)); setHiddenApiFlags(HiddenApiFlag.parse(reader)); - parseName(reader); + setName(StringKey.readSimpleName(reader, '(')); parseProto(reader); reader.skipWhitespacesOrComment(); while (parseNoneCode(reader)){ @@ -180,11 +177,6 @@ private boolean parseNoneCode(SmaliReader reader) throws IOException { } return false; } - private void parseName(SmaliReader reader) { - reader.skipWhitespaces(); - int length = reader.indexOf('(') - reader.position(); - setName(reader.readString(length)); - } private void parseProto(SmaliReader reader) throws IOException { reader.skipWhitespaces(); setProtoKey(ProtoKey.read(reader)); diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliPayloadArray.java b/src/main/java/com/reandroid/dex/smali/model/SmaliPayloadArray.java index 454ec3122..7fd2dae8d 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliPayloadArray.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliPayloadArray.java @@ -37,21 +37,12 @@ public void addEntryKeys(Iterator iterator) { public void addEntry(PrimitiveKey key) { newEntry().setKey(key); } - public int[] unsignedInt() { - SmaliSet entries = getEntries(); - int size = entries.size(); - int[] result = new int[size]; - for(int i = 0; i < size; i++){ - result[i] = entries.get(i).unsignedInt(); - } - return result; - } - public long[] unsignedLong(){ + public long[] getValuesAsLong(){ SmaliSet entries = getEntries(); int size = entries.size(); long[] result = new long[size]; for(int i = 0; i < size; i++){ - result[i] = entries.get(i).asLongValue(); + result[i] = entries.get(i).getValueAsLong(); } return result; } diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliPayloadPackedSwitch.java b/src/main/java/com/reandroid/dex/smali/model/SmaliPayloadPackedSwitch.java index a4732db26..851cc935f 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliPayloadPackedSwitch.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliPayloadPackedSwitch.java @@ -28,7 +28,7 @@ public SmaliPayloadPackedSwitch(){ } public int getFirstKey() { - return getOperand().getIntegerData(); + return (int) getOperand().getValueAsLong(); } public void setFirstKey(int firstKey) { getOperand().setNumber(firstKey); diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliValueByte.java b/src/main/java/com/reandroid/dex/smali/model/SmaliValueByte.java index e53857587..8da13dba3 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliValueByte.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliValueByte.java @@ -57,12 +57,9 @@ public void setNumber(Byte number) { public int getWidth() { return 1; } + @Override - public int unsignedInt() { - return getValue() & 0xff; - } - @Override - public long asLongValue() { + public long getValueAsLong() { return getValue(); } @Override diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliValueDouble.java b/src/main/java/com/reandroid/dex/smali/model/SmaliValueDouble.java index 57db305d5..fbaedd28a 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliValueDouble.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliValueDouble.java @@ -55,12 +55,9 @@ public void setNumber(Double number) { public int getWidth() { return 8; } + @Override - public int unsignedInt() { - return (int) getNumber().longValue(); - } - @Override - public long asLongValue() { + public long getValueAsLong() { return Double.doubleToLongBits(getValue()); } @Override diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliValueFloat.java b/src/main/java/com/reandroid/dex/smali/model/SmaliValueFloat.java index 6476166cb..059a5f845 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliValueFloat.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliValueFloat.java @@ -54,12 +54,9 @@ public void setNumber(Float number) { public int getWidth() { return 4; } + @Override - public int unsignedInt() { - return getNumber().intValue(); - } - @Override - public long asLongValue() { + public long getValueAsLong() { return Float.floatToIntBits(getValue()); } @Override diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliValueInteger.java b/src/main/java/com/reandroid/dex/smali/model/SmaliValueInteger.java index 0f01aec9c..68e90137f 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliValueInteger.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliValueInteger.java @@ -56,12 +56,9 @@ public void setNumber(Integer number) { public int getWidth() { return 4; } + @Override - public int unsignedInt() { - return getValue(); - } - @Override - public long asLongValue() { + public long getValueAsLong() { return getValue(); } @Override diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliValueLong.java b/src/main/java/com/reandroid/dex/smali/model/SmaliValueLong.java index 1a9e4eacb..a08539c5b 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliValueLong.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliValueLong.java @@ -56,12 +56,9 @@ public void setNumber(Long number) { public int getWidth() { return 8; } + @Override - public int unsignedInt() { - return (int) getValue(); - } - @Override - public long asLongValue() { + public long getValueAsLong() { return getValue(); } @Override diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliValueNumber.java b/src/main/java/com/reandroid/dex/smali/model/SmaliValueNumber.java index 2f7f2397d..de0fdc078 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliValueNumber.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliValueNumber.java @@ -19,6 +19,7 @@ import com.reandroid.dex.key.PrimitiveKey; import com.reandroid.dex.smali.SmaliParseException; import com.reandroid.dex.smali.SmaliReader; +import com.reandroid.utils.NumberX; import com.reandroid.utils.ObjectsUtil; import java.io.IOException; @@ -31,8 +32,7 @@ public SmaliValueNumber(){ public abstract T getNumber(); public abstract void setNumber(T number); public abstract int getWidth(); - public abstract int unsignedInt(); - public abstract long asLongValue(); + public abstract long getValueAsLong(); @Override public abstract PrimitiveKey getKey(); @Override @@ -81,6 +81,9 @@ private static SmaliValueNumber createUnchecked(Number number){ if(number instanceof Double){ return new SmaliValueDouble((Double) number); } + if(number instanceof NumberX){ + return new SmaliValueX((NumberX) number); + } throw new RuntimeException("Unrecognized number class: " + number.getClass()); } diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliValueShort.java b/src/main/java/com/reandroid/dex/smali/model/SmaliValueShort.java index 09c49d839..c21383a7c 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliValueShort.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliValueShort.java @@ -56,12 +56,9 @@ public void setNumber(Short number) { public int getWidth() { return 2; } + @Override - public int unsignedInt() { - return getValue() & 0xffff; - } - @Override - public long asLongValue() { + public long getValueAsLong() { return getValue(); } @Override diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliValueX.java b/src/main/java/com/reandroid/dex/smali/model/SmaliValueX.java index 42af7b2cb..44025d14d 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliValueX.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliValueX.java @@ -38,6 +38,9 @@ public SmaliValueX(int width, long value) { public SmaliValueX() { this(1, 0); } + public SmaliValueX(NumberX numberX) { + this(numberX.width(), numberX.longValue()); + } @Override public DexValueType getValueType() { @@ -46,21 +49,21 @@ public DexValueType getValueType() { @Override public void append(SmaliWriter writer) throws IOException { - writer.append(NumberX.toHexString(getWidth(), asLongValue())); + writer.append(NumberX.toHexString(getWidth(), getValueAsLong())); } @Override public void parse(SmaliReader reader) throws IOException { reader.skipSpaces(); SmaliValueNumber number = SmaliValueNumber.createNumber(reader); number.parse(reader); - long l = number.asLongValue(); + long l = number.getValueAsLong(); int width = NumbersUtil.max(this.getWidth(), NumberX.widthOfSigned(l)); set(width, l); } @Override public NumberX getNumber() { - return NumberX.valueOf(getWidth(), asLongValue()); + return NumberX.valueOf(getWidth(), getValueAsLong()); } @Override @@ -81,23 +84,19 @@ public void setWidth(int width) { } @Override - public int unsignedInt() { - return (int) asLongValue(); - } - @Override - public long asLongValue() { + public long getValueAsLong() { return value; } @Override public PrimitiveKey getKey() { - return PrimitiveKey.of(getWidth(), asLongValue()); + return PrimitiveKey.of(getWidth(), getValueAsLong()); } @Override public void setKey(Key key) { PrimitiveKey primitiveKey = (PrimitiveKey) key; if (primitiveKey.isNumber()) { - set(primitiveKey.width(), primitiveKey.asLongValue()); + set(primitiveKey.width(), primitiveKey.getValueAsLong()); } else { throw new NumberFormatException("Incompatible key: " + key.getClass() + ", " + key);