com.android.utils.SdkUtils Maven / Gradle / Ivy
/*
* Copyright (C) 2012 The Android Open Source Project
*
* 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.android.utils;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.google.common.base.CaseFormat;
import com.google.common.collect.ImmutableList;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.Properties;
import static com.android.SdkConstants.DOT_WEBP;
import static com.android.SdkConstants.DOT_PNG;
import static com.android.SdkConstants.DOT_GIF;
import static com.android.SdkConstants.DOT_9PNG;
import static com.android.SdkConstants.DOT_JPEG;
import static com.android.SdkConstants.DOT_JPG;
import static com.android.SdkConstants.DOT_BMP;
/** Miscellaneous utilities used by the Android SDK tools */
public class SdkUtils {
/**
* Returns true if the given string ends with the given suffix, using a
* case-insensitive comparison.
*
* @param string the full string to be checked
* @param suffix the suffix to be checked for
* @return true if the string case-insensitively ends with the given suffix
*/
public static boolean endsWithIgnoreCase(@NonNull String string, @NonNull String suffix) {
return string.regionMatches(true /* ignoreCase */, string.length() - suffix.length(),
suffix, 0, suffix.length());
}
/**
* Returns true if the given sequence ends with the given suffix (case
* sensitive).
*
* @param sequence the character sequence to be checked
* @param suffix the suffix to look for
* @return true if the given sequence ends with the given suffix
*/
public static boolean endsWith(@NonNull CharSequence sequence, @NonNull CharSequence suffix) {
return endsWith(sequence, sequence.length(), suffix);
}
/**
* Returns true if the given sequence ends at the given offset with the given suffix (case
* sensitive)
*
* @param sequence the character sequence to be checked
* @param endOffset the offset at which the sequence is considered to end
* @param suffix the suffix to look for
* @return true if the given sequence ends with the given suffix
*/
public static boolean endsWith(@NonNull CharSequence sequence, int endOffset,
@NonNull CharSequence suffix) {
if (endOffset < suffix.length()) {
return false;
}
for (int i = endOffset - 1, j = suffix.length() - 1; j >= 0; i--, j--) {
if (sequence.charAt(i) != suffix.charAt(j)) {
return false;
}
}
return true;
}
/**
* Returns true if the given string starts with the given prefix, using a
* case-insensitive comparison.
*
* @param string the full string to be checked
* @param prefix the prefix to be checked for
* @return true if the string case-insensitively starts with the given prefix
*/
public static boolean startsWithIgnoreCase(@NonNull String string, @NonNull String prefix) {
return string.regionMatches(true /* ignoreCase */, 0, prefix, 0, prefix.length());
}
/** For use by {@link #getLineSeparator()} */
private static String sLineSeparator;
/**
* Returns the default line separator to use.
*
* NOTE: If you have an associated IDocument (Eclipse), it is better to call
* TextUtilities#getDefaultLineDelimiter(IDocument) since that will
* allow (for example) editing a \r\n-delimited document on a \n-delimited
* platform and keep a consistent usage of delimiters in the file.
*
* @return the delimiter string to use
*/
@NonNull
public static String getLineSeparator() {
if (sLineSeparator == null) {
// This is guaranteed to exist:
sLineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$
}
return sLineSeparator;
}
/**
* Wraps the given text at the given line width, with an optional hanging
* indent.
*
* @param text the text to be wrapped
* @param lineWidth the number of characters to wrap the text to
* @param hangingIndent the hanging indent (to be used for the second and
* subsequent lines in each paragraph, or null if not known
* @return the string, wrapped
*/
@NonNull
public static String wrap(
@NonNull String text,
int lineWidth,
@Nullable String hangingIndent) {
if (hangingIndent == null) {
hangingIndent = "";
}
int explanationLength = text.length();
StringBuilder sb = new StringBuilder(explanationLength * 2);
int index = 0;
while (index < explanationLength) {
int lineEnd = text.indexOf('\n', index);
int next;
if (lineEnd != -1 && (lineEnd - index) < lineWidth) {
next = lineEnd + 1;
} else {
// Line is longer than available width; grab as much as we can
lineEnd = Math.min(index + lineWidth, explanationLength);
if (lineEnd - index < lineWidth) {
next = explanationLength;
} else {
// then back up to the last space
int lastSpace = text.lastIndexOf(' ', lineEnd);
if (lastSpace > index) {
lineEnd = lastSpace;
next = lastSpace + 1;
} else {
// No space anywhere on the line: it contains something wider than
// can fit (like a long URL) so just hard break it
next = lineEnd + 1;
}
}
}
if (sb.length() > 0) {
sb.append(hangingIndent);
} else {
lineWidth -= hangingIndent.length();
}
sb.append(text.substring(index, lineEnd));
sb.append('\n');
index = next;
}
return sb.toString();
}
/**
* Returns the corresponding {@link File} for the given file:// url
*
* @param url the URL string, e.g. file://foo/bar
* @return the corresponding {@link File} (which may or may not exist)
* @throws MalformedURLException if the URL string is malformed or is not a file: URL
*/
@NonNull
public static File urlToFile(@NonNull String url) throws MalformedURLException {
return urlToFile(new URL(url));
}
@NonNull
public static File urlToFile(@NonNull URL url) throws MalformedURLException {
try {
return new File(url.toURI());
}
catch (IllegalArgumentException e) {
MalformedURLException ex = new MalformedURLException(e.getLocalizedMessage());
ex.initCause(e);
throw ex;
}
catch (URISyntaxException e) {
return new File(url.getPath());
}
}
/**
* Returns the corresponding URL string for the given {@link File}
*
* @param file the file to look up the URL for
* @return the corresponding URL
* @throws MalformedURLException in very unexpected cases
*/
public static String fileToUrlString(@NonNull File file) throws MalformedURLException {
String url = fileToUrl(file).toExternalForm();
// Use three slashes, which is the form most widely recognized by terminal emulators.
if (!url.startsWith("file:///")) {
url = url.replaceFirst("file:/", "file:///");
}
return url;
}
/**
* Returns the corresponding URL for the given {@link File}
*
* @param file the file to look up the URL for
* @return the corresponding URL
* @throws MalformedURLException in very unexpected cases
*/
public static URL fileToUrl(@NonNull File file) throws MalformedURLException {
return file.toURI().toURL();
}
/** Prefix in comments which mark the source locations for merge results */
public static final String FILENAME_PREFIX = "From: ";
/**
* Creates the path comment XML string. Note that it does not escape characters
* such as & and <; those are expected to be escaped by the caller (for
* example, handled by a call to {@link org.w3c.dom.Document#createComment(String)})
*
*
* @param file the file to create a path comment for
* @param includePadding whether to include padding. The final comment recognized by
* error recognizers expect padding between the {@code