diff options
author | Mel Carr Zúñiga <melisacz@google.com> | 2024-01-05 15:57:59 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-05 15:57:59 +0100 |
commit | 80bf6209cbd3e6b94b1b58bf6d81c6fa6e1bcceb (patch) | |
tree | f233eb937c639b4430e8a53b8443a1c15d88d9a3 | |
parent | 27a1717337c413364484df0e12e42df7d4fc9d0a (diff) | |
download | google-smali-80bf6209cbd3e6b94b1b58bf6d81c6fa6e1bcceb.tar.gz |
Reducing usage of guava libraries in dexlib2 and dexlib2/base (#25)
Part 1/n
12 files changed, 127 insertions, 60 deletions
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/DexFileFactory.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/DexFileFactory.java index 06698c8c..e7cefa17 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/DexFileFactory.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/DexFileFactory.java @@ -30,14 +30,12 @@ package com.android.tools.smali.dexlib2; +import static java.util.Collections.unmodifiableList; + import com.android.tools.smali.dexlib2.iface.DexFile; import com.android.tools.smali.dexlib2.iface.MultiDexContainer; import com.android.tools.smali.dexlib2.iface.MultiDexContainer.DexEntry; -import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.io.ByteStreams; -import com.google.common.io.Files; + import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile; import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile.NotADexFile; import com.android.tools.smali.dexlib2.dexbacked.DexBackedOdexFile; @@ -48,6 +46,7 @@ import com.android.tools.smali.dexlib2.dexbacked.ZipDexContainer; import com.android.tools.smali.dexlib2.dexbacked.ZipDexContainer.NotAZipFileException; import com.android.tools.smali.dexlib2.writer.pool.DexPool; import com.android.tools.smali.util.ExceptionWithContext; +import com.android.tools.smali.util.StringUtils; import java.io.BufferedInputStream; import java.io.File; @@ -57,6 +56,8 @@ import java.io.IOException; import java.io.InputStream; import javax.annotation.Nonnull; import javax.annotation.Nullable; + +import java.util.ArrayList; import java.util.List; public final class DexFileFactory { @@ -395,10 +396,10 @@ public final class DexFileFactory { } // find all full and partial matches - List<String> fullMatches = Lists.newArrayList(); - List<MultiDexContainer.DexEntry<? extends DexBackedDexFile>> fullEntries = Lists.newArrayList(); - List<String> partialMatches = Lists.newArrayList(); - List<MultiDexContainer.DexEntry<? extends DexBackedDexFile>> partialEntries = Lists.newArrayList(); + List<String> fullMatches = new ArrayList<>(); + List<MultiDexContainer.DexEntry<? extends DexBackedDexFile>> fullEntries = new ArrayList<>(); + List<String> partialMatches = new ArrayList<>(); + List<MultiDexContainer.DexEntry<? extends DexBackedDexFile>> partialEntries = new ArrayList<>(); for (String entry: dexContainer.getDexEntryNames()) { if (fullEntryMatch(entry, targetEntry)) { // We want to grab all full matches, regardless of whether they're actually a dex file. @@ -430,7 +431,8 @@ public final class DexFileFactory { // only by an initial path separator. e.g. "/blah/blah.dex" and "blah/blah.dex" throw new MultipleMatchingDexEntriesException(String.format( "Multiple entries in %s match %s: %s", filename, targetEntry, - Joiner.on(", ").join(fullMatches))); + StringUtils.join(fullMatches, ", ") + )); } if (partialEntries.size() == 0) { @@ -440,7 +442,8 @@ public final class DexFileFactory { if (partialEntries.size() > 1) { throw new MultipleMatchingDexEntriesException(String.format( "Multiple dex entries in %s match %s: %s", filename, targetEntry, - Joiner.on(", ").join(partialMatches))); + StringUtils.join(partialMatches, ", ") + )); } return partialEntries.get(0); } @@ -456,7 +459,7 @@ public final class DexFileFactory { } @Nonnull @Override public List<String> getDexEntryNames() { - return ImmutableList.of(entryName); + return unmodifiableList(List.of(entryName)); } @Nullable @Override public DexEntry<DexBackedDexFile> getEntry(@Nonnull String entryName) { @@ -494,7 +497,7 @@ public final class DexFileFactory { public FilenameVdexProvider(File oatFile) { File oatParent = oatFile.getAbsoluteFile().getParentFile(); - String baseName = Files.getNameWithoutExtension(oatFile.getAbsolutePath()); + String baseName = getNameWithoutExtension(oatFile.getAbsolutePath()); vdexFile = new File(oatParent, baseName + ".vdex"); } @@ -515,7 +518,10 @@ public final class DexFileFactory { if (candidateFile.exists()) { try { - buf = ByteStreams.toByteArray(new FileInputStream(candidateFile)); + FileInputStream fis = new FileInputStream(candidateFile); + int fileSize = fis.available(); + buf = new byte[fileSize]; + fis.read(buf); } catch (FileNotFoundException e) { buf = null; } catch (IOException ex) { @@ -527,5 +533,11 @@ public final class DexFileFactory { return buf; } + + public static String getNameWithoutExtension(String file) { + String fileName = new File(file).getName(); + int dotIndex = fileName.lastIndexOf('.'); + return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex); + } } } diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/HiddenApiRestriction.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/HiddenApiRestriction.java index 2f1683a0..f1e697d5 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/HiddenApiRestriction.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/HiddenApiRestriction.java @@ -30,10 +30,10 @@ package com.android.tools.smali.dexlib2; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSet.Builder; +import static java.util.Collections.unmodifiableSet; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.StringJoiner; @@ -107,19 +107,20 @@ public enum HiddenApiRestriction { public static Set<HiddenApiRestriction> getAllFlags(int value) { HiddenApiRestriction normalRestriction = hiddenApiFlags[value & HIDDENAPI_FLAG_MASK]; + HashSet restrictionSet = new HashSet<HiddenApiRestriction>(); int domainSpecificPart = (value & ~HIDDENAPI_FLAG_MASK); if (domainSpecificPart == 0) { - return ImmutableSet.of(normalRestriction); + restrictionSet.add(normalRestriction); + return unmodifiableSet(restrictionSet); } - Builder<HiddenApiRestriction> builder = ImmutableSet.builder(); - builder.add(normalRestriction); + restrictionSet.add(normalRestriction); for (HiddenApiRestriction domainSpecificApiFlag : domainSpecificApiFlags) { if (domainSpecificApiFlag.isSet(value)) { - builder.add(domainSpecificApiFlag); + restrictionSet.add(domainSpecificApiFlag); } } - return builder.build(); + return unmodifiableSet(restrictionSet); } public static String formatHiddenRestrictions(int value) { diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/MethodHandleType.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/MethodHandleType.java index 27a6b611..6ba1726b 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/MethodHandleType.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/MethodHandleType.java @@ -30,8 +30,11 @@ package com.android.tools.smali.dexlib2; -import com.google.common.collect.BiMap; -import com.google.common.collect.ImmutableBiMap; +import static java.util.Collections.unmodifiableMap; + +import java.util.HashMap; +import java.util.Map; + import com.android.tools.smali.util.ExceptionWithContext; import javax.annotation.Nonnull; @@ -47,17 +50,26 @@ public class MethodHandleType { public static final int INVOKE_DIRECT = 7; public static final int INVOKE_INTERFACE = 8; - private static final BiMap<Integer, String> methodHandleTypeNames = new ImmutableBiMap.Builder<Integer, String>() - .put(STATIC_PUT, "static-put") - .put(STATIC_GET, "static-get") - .put(INSTANCE_PUT, "instance-put") - .put(INSTANCE_GET, "instance-get") - .put(INVOKE_STATIC, "invoke-static") - .put(INVOKE_INSTANCE, "invoke-instance") - .put(INVOKE_CONSTRUCTOR, "invoke-constructor") - .put(INVOKE_DIRECT, "invoke-direct") - .put(INVOKE_INTERFACE, "invoke-interface") - .build(); + private static final Map<Integer, String> methodHandleTypeNames = unmodifiableMap(Map.of( + STATIC_PUT, "static-put", + STATIC_GET, "static-get", + INSTANCE_PUT, "instance-put", + INSTANCE_GET, "instance-get", + INVOKE_STATIC, "invoke-static", + INVOKE_INSTANCE, "invoke-instance", + INVOKE_CONSTRUCTOR, "invoke-constructor", + INVOKE_DIRECT, "invoke-direct", + INVOKE_INTERFACE, "invoke-interface")); + + private static final Map<String, Integer> inverse = getInverse(); + + private static Map<String, Integer> getInverse() { + HashMap<String, Integer> namesToTypes = new HashMap<>(); + for (Map.Entry<Integer, String> entry : methodHandleTypeNames.entrySet()) { + namesToTypes.put(entry.getValue(), entry.getKey()); + } + return unmodifiableMap(namesToTypes); + } @Nonnull public static String toString(int methodHandleType) { String val = methodHandleTypeNames.get(methodHandleType); @@ -68,7 +80,7 @@ public class MethodHandleType { } public static int getMethodHandleType(String methodHandleType) { - Integer ret = methodHandleTypeNames.inverse().get(methodHandleType); + Integer ret = inverse.get(methodHandleType); if (ret == null) { throw new ExceptionWithContext("Invalid method handle type: %s", methodHandleType); } diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcodes.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcodes.java index 5a88b0db..176c5175 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcodes.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcodes.java @@ -30,7 +30,6 @@ package com.android.tools.smali.dexlib2; -import com.google.common.collect.Maps; import com.google.common.collect.RangeMap; import javax.annotation.Nonnull; @@ -94,7 +93,7 @@ public class Opcodes { } opcodeValues = new EnumMap<Opcode, Short>(Opcode.class); - opcodesByName = Maps.newHashMap(); + opcodesByName = new HashMap<>(); int version; if (isArt()) { diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VerificationError.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VerificationError.java index d4315886..f7282d7c 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VerificationError.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VerificationError.java @@ -30,7 +30,6 @@ package com.android.tools.smali.dexlib2; -import com.google.common.collect.Maps; import com.android.tools.smali.util.ExceptionWithContext; import javax.annotation.Nullable; @@ -47,7 +46,7 @@ public class VerificationError { public static final int CLASS_CHANGE_ERROR = 8; public static final int INSTANTIATION_ERROR = 9; - private static final HashMap<String, Integer> verificationErrorNames = Maps.newHashMap(); + private static final HashMap<String, Integer> verificationErrorNames = new HashMap<>(); static { verificationErrorNames.put("generic-error", GENERIC); diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseAnnotation.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseAnnotation.java index 5dd2e603..f271c429 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseAnnotation.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseAnnotation.java @@ -31,7 +31,6 @@ package com.android.tools.smali.dexlib2.base; import com.android.tools.smali.dexlib2.iface.Annotation; -import com.google.common.primitives.Ints; import com.android.tools.smali.util.CollectionUtils; import java.util.Comparator; @@ -57,7 +56,7 @@ public abstract class BaseAnnotation implements Annotation { @Override public int compareTo(Annotation o) { - int res = Ints.compare(getVisibility(), o.getVisibility()); + int res = Integer.compare(getVisibility(), o.getVisibility()); if (res != 0) return res; res = getType().compareTo(o.getType()); if (res != 0) return res; diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseExceptionHandler.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseExceptionHandler.java index 32ca007f..5f6d098a 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseExceptionHandler.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseExceptionHandler.java @@ -31,14 +31,13 @@ package com.android.tools.smali.dexlib2.base; import com.android.tools.smali.dexlib2.iface.ExceptionHandler; -import com.google.common.base.Objects; -import com.google.common.primitives.Ints; import com.android.tools.smali.dexlib2.base.reference.BaseTypeReference; import com.android.tools.smali.dexlib2.iface.reference.TypeReference; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Comparator; +import java.util.Objects; public abstract class BaseExceptionHandler implements ExceptionHandler { @Nullable @Override public TypeReference getExceptionTypeReference() { @@ -65,7 +64,7 @@ public abstract class BaseExceptionHandler implements ExceptionHandler { public boolean equals(@Nullable Object o) { if (o instanceof ExceptionHandler) { ExceptionHandler other = (ExceptionHandler)o; - return Objects.equal(getExceptionType(), other.getExceptionType()) && + return Objects.equals(getExceptionType(), other.getExceptionType()) && (getHandlerCodeAddress() == other.getHandlerCodeAddress()); } return false; @@ -87,7 +86,7 @@ public abstract class BaseExceptionHandler implements ExceptionHandler { res = exceptionType.compareTo(o.getExceptionType()); if (res != 0) return res; } - return Ints.compare(getHandlerCodeAddress(), o.getHandlerCodeAddress()); + return Integer.compare(getHandlerCodeAddress(), o.getHandlerCodeAddress()); } diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodHandleReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodHandleReference.java index e14b23a4..f2d4e842 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodHandleReference.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodHandleReference.java @@ -34,7 +34,6 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference; import com.android.tools.smali.dexlib2.iface.reference.MethodHandleReference; import com.android.tools.smali.dexlib2.iface.reference.MethodReference; import com.android.tools.smali.dexlib2.iface.reference.Reference; -import com.google.common.primitives.Ints; import com.android.tools.smali.dexlib2.formatter.DexFormatter; import javax.annotation.Nonnull; @@ -60,7 +59,7 @@ public abstract class BaseMethodHandleReference extends BaseReference implements @Override public int compareTo(@Nonnull MethodHandleReference o) { - int res = Ints.compare(getMethodHandleType(), o.getMethodHandleType()); + int res = Integer.compare(getMethodHandleType(), o.getMethodHandleType()); if (res != 0) return res; Reference reference = getMemberReference(); diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodProtoReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodProtoReference.java index 4a1309ef..b43e6647 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodProtoReference.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodProtoReference.java @@ -33,7 +33,6 @@ package com.android.tools.smali.dexlib2.base.reference; import com.android.tools.smali.dexlib2.iface.reference.MethodProtoReference; import com.android.tools.smali.util.CharSequenceUtils; import com.android.tools.smali.util.CollectionUtils; -import com.google.common.collect.Ordering; import com.android.tools.smali.dexlib2.formatter.DexFormatter; import javax.annotation.Nonnull; @@ -62,7 +61,8 @@ public abstract class BaseMethodProtoReference extends BaseReference implements public int compareTo(@Nonnull MethodProtoReference o) { int res = getReturnType().compareTo(o.getReturnType()); if (res != 0) return res; - return CollectionUtils.compareAsIterable(Ordering.usingToString(), getParameterTypes(), o.getParameterTypes()); + return CollectionUtils.compareAsIterable( + CollectionUtils.usingToStringOrdering(), getParameterTypes(), o.getParameterTypes()); } @Override public String toString() { diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodReference.java index 079b073f..5fda22a3 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodReference.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodReference.java @@ -33,7 +33,6 @@ package com.android.tools.smali.dexlib2.base.reference; import com.android.tools.smali.dexlib2.iface.reference.MethodReference; import com.android.tools.smali.util.CharSequenceUtils; import com.android.tools.smali.util.CollectionUtils; -import com.google.common.collect.Ordering; import com.android.tools.smali.dexlib2.formatter.DexFormatter; import javax.annotation.Nonnull; @@ -68,7 +67,8 @@ public abstract class BaseMethodReference extends BaseReference implements Metho if (res != 0) return res; res = getReturnType().compareTo(o.getReturnType()); if (res != 0) return res; - return CollectionUtils.compareAsIterable(Ordering.usingToString(), getParameterTypes(), o.getParameterTypes()); + return CollectionUtils.compareAsIterable( + CollectionUtils.usingToStringOrdering(), getParameterTypes(), o.getParameterTypes()); } @Override public String toString() { diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/CollectionUtils.java b/dexlib2/src/main/java/com/android/tools/smali/util/CollectionUtils.java index 75bf7f9c..2fe222af 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/util/CollectionUtils.java +++ b/dexlib2/src/main/java/com/android/tools/smali/util/CollectionUtils.java @@ -32,13 +32,13 @@ package com.android.tools.smali.util; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableSortedSet; -import com.google.common.collect.Ordering; -import com.google.common.primitives.Ints; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.SortedSet; + import javax.annotation.Nonnull; public class CollectionUtils { @@ -64,7 +64,7 @@ public class CollectionUtils { public static <T extends Comparable<? super T>> int compareAsList(@Nonnull Collection<? extends T> list1, @Nonnull Collection<? extends T> list2) { - int res = Ints.compare(list1.size(), list2.size()); + int res = Integer.compare(list1.size(), list2.size()); if (res != 0) return res; Iterator<? extends T> elements2 = list2.iterator(); for (T element1: list1) { @@ -114,7 +114,7 @@ public class CollectionUtils { public static <T> int compareAsList(@Nonnull Comparator<? super T> elementComparator, @Nonnull Collection<? extends T> list1, @Nonnull Collection<? extends T> list2) { - int res = Ints.compare(list1.size(), list2.size()); + int res = Integer.compare(list1.size(), list2.size()); if (res != 0) return res; Iterator<? extends T> elements2 = list2.iterator(); for (T element1: list1) { @@ -139,7 +139,7 @@ public class CollectionUtils { if (it instanceof SortedSet) { SortedSet<? extends T> sortedSet = (SortedSet<? extends T>)it; Comparator<?> comparator = sortedSet.comparator(); - return (comparator == null) || comparator.equals(Ordering.natural()); + return (comparator == null) || comparator.equals(NaturalOrdering.INSTANCE); } return false; } @@ -150,7 +150,7 @@ public class CollectionUtils { SortedSet<? extends T> sortedSet = (SortedSet<? extends T>)it; Comparator<?> comparator = sortedSet.comparator(); if (comparator == null) { - return elementComparator.equals(Ordering.natural()); + return elementComparator.equals(NaturalOrdering.INSTANCE); } return elementComparator.equals(comparator); } @@ -162,7 +162,8 @@ public class CollectionUtils { if (isNaturalSortedSet(collection)) { return (SortedSet<? extends T>)collection; } - return ImmutableSortedSet.copyOf(collection); + SortedSet<? extends T> sortedSet = ArraySortedSet.of(NaturalOrdering.INSTANCE, collection.toArray()); + return Collections.unmodifiableSortedSet(sortedSet); } @Nonnull @@ -175,6 +176,7 @@ public class CollectionUtils { return sortedSet; } } + return ImmutableSortedSet.copyOf(elementComparator, collection); } @@ -191,7 +193,7 @@ public class CollectionUtils { public static <T extends Comparable<T>> int compareAsSet(@Nonnull Collection<? extends T> set1, @Nonnull Collection<? extends T> set2) { - int res = Ints.compare(set1.size(), set2.size()); + int res = Integer.compare(set1.size(), set2.size()); if (res != 0) return res; SortedSet<? extends T> sortedSet1 = toNaturalSortedSet(set1); @@ -208,7 +210,7 @@ public class CollectionUtils { public static <T> int compareAsSet(@Nonnull Comparator<? super T> elementComparator, @Nonnull Collection<? extends T> list1, @Nonnull Collection<? extends T> list2) { - int res = Ints.compare(list1.size(), list2.size()); + int res = Integer.compare(list1.size(), list2.size()); if (res != 0) return res; SortedSet<? extends T> set1 = toSortedSet(elementComparator, list1); @@ -221,4 +223,34 @@ public class CollectionUtils { } return 0; } + + public static <T> Comparator<? super T> usingToStringOrdering() { + return UsingToStringOrdering.INSTANCE; + } + + public static <T> Comparator<? super T> naturalOrdering() { + return NaturalOrdering.INSTANCE; + } + + public final static class UsingToStringOrdering<T extends Object> implements Comparator<T> { + static final UsingToStringOrdering INSTANCE = new UsingToStringOrdering(); + + @Override + public int compare(Object left, Object right) { + return left.toString().compareTo(right.toString()); + } + + private UsingToStringOrdering() {} + } + + public final static class NaturalOrdering<T extends Comparable<? super T>> implements Comparator<T> { + static final NaturalOrdering INSTANCE = new NaturalOrdering(); + + @Override + public int compare(T left, T right) { + return left.compareTo(right); + } + + private NaturalOrdering() {} + } } diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/StringUtils.java b/dexlib2/src/main/java/com/android/tools/smali/util/StringUtils.java index 4c567d17..730caa8f 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/util/StringUtils.java +++ b/dexlib2/src/main/java/com/android/tools/smali/util/StringUtils.java @@ -33,6 +33,8 @@ package com.android.tools.smali.util; import com.android.tools.smali.dexlib2.formatter.DexFormattedWriter; import java.io.IOException; import java.io.Writer; +import java.util.Iterator; +import java.util.List; public class StringUtils { @@ -122,4 +124,17 @@ public class StringUtils { return sb.toString(); } + + public static String join(List<? extends Object> parts, String separator) { + StringBuilder builder = new StringBuilder(); + Iterator<? extends Object> it = parts.iterator(); + if (it.hasNext()) { + builder.append(it.hasNext()); + } + while (it.hasNext()) { + builder.append(separator); + builder.append(it.next()); + } + return builder.toString(); + } } |