Apktool/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/TypeName.java

213 lines
6.2 KiB
Java

/**
* Copyright 2014 Ryszard Wiśniewski <brut.alll@gmail.com>
*
* 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 brut.androlib.src;
import brut.androlib.AndrolibException;
import brut.util.Duo;
import com.google.common.base.Joiner;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
public class TypeName {
public final String package_;
public final String type;
public final String innerType;
public final int array;
public TypeName(String type, int array) {
this(null, type, null, array);
}
public TypeName(String package_, String type, String innerType, int array) {
this.package_ = package_;
this.type = type;
this.innerType = innerType;
this.array = array;
}
public String getShortenedName() {
return getName("java.lang".equals(package_), isFileOwner());
}
public String getName() {
return getName(false, false);
}
public String getName(boolean excludePackage, boolean separateInner) {
String name = (package_ == null || excludePackage ? "" : package_ + '.')
+ type
+ (innerType != null ? (separateInner ? '$' : '.') + innerType
: "");
for (int i = 0; i < array; i++) {
name += "[]";
}
return name;
}
public String getJavaFilePath() {
return getFilePath(isFileOwner()) + ".java";
}
public String getSmaliFilePath() {
return getFilePath(true) + ".smali";
}
public String getFilePath(boolean separateInner) {
return package_.replace('.', File.separatorChar) + File.separatorChar
+ type + (separateInner && isInner() ? "$" + innerType : "");
}
public boolean isInner() {
return innerType != null;
}
public boolean isArray() {
return array != 0;
}
public boolean isFileOwner() {
if (mIsFileOwner == null) {
mIsFileOwner = true;
if (isInner()) {
char c = innerType.charAt(0);
if (c < '0' || c > '9') {
mIsFileOwner = false;
}
}
}
return mIsFileOwner;
}
@Override
public String toString() {
return getName();
}
public static TypeName fromInternalName(String internal)
throws AndrolibException {
Duo<TypeName, Integer> duo = fetchFromInternalName(internal);
if (duo.m2 != internal.length()) {
throw new AndrolibException("Invalid internal name: " + internal);
}
return duo.m1;
}
public static List<TypeName> listFromInternalName(String internal)
throws AndrolibException {
List<TypeName> types = new ArrayList<TypeName>();
while (!internal.isEmpty()) {
Duo<TypeName, Integer> duo = fetchFromInternalName(internal);
types.add(duo.m1);
internal = internal.substring(duo.m2);
}
return types;
}
public static TypeName fromPath(Path path) {
List<String> parts = new ArrayList<>(path.getNameCount());
for (Path p : path) {
parts.add(p.toString());
}
return fromNameParts(parts, 0);
}
public static TypeName fromNameParts(List<String> parts, int array) {
String type = parts.get(parts.size() - 1);
parts = parts.subList(0, parts.size() - 1);
String innerType = null;
int pos = type.indexOf('$');
if (pos != -1) {
innerType = type.substring(pos + 1);
type = type.substring(0, pos);
}
return new TypeName(Joiner.on('.').join(parts), type, innerType, array);
}
public static Duo<TypeName, Integer> fetchFromInternalName(String internal)
throws AndrolibException {
String origInternal = internal;
int array = 0;
boolean isArray = false;
do {
if (internal.isEmpty()) {
throw new AndrolibException("Invalid internal name: "
+ origInternal);
}
isArray = internal.charAt(0) == '[';
if (isArray) {
array++;
internal = internal.substring(1);
}
} while (isArray);
int length = array + 1;
String type;
switch (internal.charAt(0)) {
case 'B':
type = "byte";
break;
case 'C':
type = "char";
break;
case 'D':
type = "double";
break;
case 'F':
type = "float";
break;
case 'I':
type = "int";
break;
case 'J':
type = "long";
break;
case 'S':
type = "short";
break;
case 'Z':
type = "boolean";
break;
case 'V':
type = "void";
break;
case 'L':
int pos = internal.indexOf(';');
if (pos == -1) {
throw new AndrolibException("Invalid internal name: "
+ origInternal);
}
return new Duo<>(fromNameParts(Arrays.asList(internal.substring(1, pos).split("/")), array), length + pos);
default:
throw new AndrolibException("Invalid internal name: "
+ origInternal);
}
return new Duo<>(new TypeName(null, type, null, array), length);
}
private Boolean mIsFileOwner;
}