|
|
@ -19,6 +19,7 @@ |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
package org.airsonic.player.util; |
|
|
|
package org.airsonic.player.util; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import org.apache.commons.codec.DecoderException; |
|
|
|
import org.apache.commons.codec.binary.Hex; |
|
|
|
import org.apache.commons.codec.binary.Hex; |
|
|
|
import org.apache.commons.lang.StringUtils; |
|
|
|
import org.apache.commons.lang.StringUtils; |
|
|
|
|
|
|
|
|
|
|
@ -28,11 +29,11 @@ import java.net.URL; |
|
|
|
import java.net.URLDecoder; |
|
|
|
import java.net.URLDecoder; |
|
|
|
import java.net.URLEncoder; |
|
|
|
import java.net.URLEncoder; |
|
|
|
import java.nio.charset.StandardCharsets; |
|
|
|
import java.nio.charset.StandardCharsets; |
|
|
|
import java.security.MessageDigest; |
|
|
|
|
|
|
|
import java.text.*; |
|
|
|
import java.text.*; |
|
|
|
import java.util.*; |
|
|
|
import java.util.*; |
|
|
|
import java.util.regex.Matcher; |
|
|
|
import java.util.regex.Matcher; |
|
|
|
import java.util.regex.Pattern; |
|
|
|
import java.util.regex.Pattern; |
|
|
|
|
|
|
|
import java.util.stream.Stream; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Miscellaneous string utility methods. |
|
|
|
* Miscellaneous string utility methods. |
|
|
@ -42,15 +43,8 @@ import java.util.regex.Pattern; |
|
|
|
public final class StringUtil { |
|
|
|
public final class StringUtil { |
|
|
|
|
|
|
|
|
|
|
|
public static final String ENCODING_UTF8 = "UTF-8"; |
|
|
|
public static final String ENCODING_UTF8 = "UTF-8"; |
|
|
|
private static final DateFormat ISO_8601_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); |
|
|
|
|
|
|
|
|
|
|
|
private static final Pattern SPLIT_PATTERN = Pattern.compile("\"([^\"]*)\"|(\\S+)"); |
|
|
|
private static final String[][] HTML_SUBSTITUTIONS = { |
|
|
|
|
|
|
|
{"&", "&"}, |
|
|
|
|
|
|
|
{"<", "<"}, |
|
|
|
|
|
|
|
{">", ">"}, |
|
|
|
|
|
|
|
{"'", "'"}, |
|
|
|
|
|
|
|
{"\"", """}, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final String[][] MIME_TYPES = { |
|
|
|
private static final String[][] MIME_TYPES = { |
|
|
|
{"mp3", "audio/mpeg"}, |
|
|
|
{"mp3", "audio/mpeg"}, |
|
|
@ -98,58 +92,6 @@ public final class StringUtil { |
|
|
|
private StringUtil() { |
|
|
|
private StringUtil() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Returns the specified string converted to a format suitable for |
|
|
|
|
|
|
|
* HTML. All single-quote, double-quote, greater-than, less-than and |
|
|
|
|
|
|
|
* ampersand characters are replaces with their corresponding HTML |
|
|
|
|
|
|
|
* Character Entity code. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param s the string to convert |
|
|
|
|
|
|
|
* @return the converted string |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static String toHtml(String s) { |
|
|
|
|
|
|
|
if (s == null) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (String[] substitution : HTML_SUBSTITUTIONS) { |
|
|
|
|
|
|
|
if (s.contains(substitution[0])) { |
|
|
|
|
|
|
|
s = s.replaceAll(substitution[0], substitution[1]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return s; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Formats the given date to a ISO-8601 date/time format, and UTC timezone. |
|
|
|
|
|
|
|
* <p/> |
|
|
|
|
|
|
|
* The returned date uses the following format: 2007-12-17T14:57:17 |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param date The date to format |
|
|
|
|
|
|
|
* @return The corresponding ISO-8601 formatted string. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static String toISO8601(Date date) { |
|
|
|
|
|
|
|
if (date == null) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
synchronized (ISO_8601_DATE_FORMAT) { |
|
|
|
|
|
|
|
return ISO_8601_DATE_FORMAT.format(date); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Removes the suffix (the substring after the last dot) of the given string. The dot is |
|
|
|
|
|
|
|
* also removed. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param s The string in question, e.g., "foo.mp3". |
|
|
|
|
|
|
|
* @return The string without the suffix, e.g., "foo". |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static String removeSuffix(String s) { |
|
|
|
|
|
|
|
int index = s.lastIndexOf('.'); |
|
|
|
|
|
|
|
return index == -1 ? s : s.substring(0, index); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Returns the proper MIME type for the given suffix. |
|
|
|
* Returns the proper MIME type for the given suffix. |
|
|
|
* |
|
|
|
* |
|
|
@ -269,16 +211,14 @@ public final class StringUtil { |
|
|
|
return new String[0]; |
|
|
|
return new String[0]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Pattern pattern = Pattern.compile("\".*?\"|\\S+"); |
|
|
|
List<String> result = new ArrayList<>(); |
|
|
|
Matcher matcher = pattern.matcher(input); |
|
|
|
Matcher m = SPLIT_PATTERN.matcher(input); |
|
|
|
|
|
|
|
while (m.find()) { |
|
|
|
List<String> result = new ArrayList<String>(); |
|
|
|
if (m.group(1) != null) { |
|
|
|
while (matcher.find()) { |
|
|
|
result.add(m.group(1)); // quoted string
|
|
|
|
String element = matcher.group(); |
|
|
|
} else { |
|
|
|
if (element.startsWith("\"") && element.endsWith("\"") && element.length() > 1) { |
|
|
|
result.add(m.group(2)); // unquoted string
|
|
|
|
element = element.substring(1, element.length() - 1); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
result.add(element); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return result.toArray(new String[result.size()]); |
|
|
|
return result.toArray(new String[result.size()]); |
|
|
@ -320,21 +260,9 @@ public final class StringUtil { |
|
|
|
return new int[0]; |
|
|
|
return new int[0]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
String[] strings = StringUtils.split(s); |
|
|
|
return Stream.of(StringUtils.split(s)) |
|
|
|
int[] ints = new int[strings.length]; |
|
|
|
.mapToInt(Integer::parseInt) |
|
|
|
for (int i = 0; i < strings.length; i++) { |
|
|
|
.toArray(); |
|
|
|
ints[i] = Integer.parseInt(strings[i]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return ints; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Determines whether a is equal to b, taking null into account. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Whether a and b are equal, or both null. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static boolean isEqual(Object a, Object b) { |
|
|
|
|
|
|
|
return Objects.equals(a, b); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
@ -348,18 +276,11 @@ public final class StringUtil { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
String[] elements = s.split("_"); |
|
|
|
List<String> elements = new ArrayList<>(Arrays.asList(s.split("_", 3))); |
|
|
|
|
|
|
|
while (elements.size() < 3) { |
|
|
|
if (elements.length == 0) { |
|
|
|
elements.add(""); |
|
|
|
return new Locale(s, "", ""); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (elements.length == 1) { |
|
|
|
|
|
|
|
return new Locale(elements[0], "", ""); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
if (elements.length == 2) { |
|
|
|
return new Locale(elements.get(0), elements.get(1), elements.get(2)); |
|
|
|
return new Locale(elements[0], elements[1], ""); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return new Locale(elements[0], elements[1], elements[2]); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
@ -404,34 +325,15 @@ public final class StringUtil { |
|
|
|
* |
|
|
|
* |
|
|
|
* @param s The string to decode. |
|
|
|
* @param s The string to decode. |
|
|
|
* @return The decoded string. |
|
|
|
* @return The decoded string. |
|
|
|
* @throws Exception If an error occurs. |
|
|
|
* @throws DecoderException If an error occurs. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static String utf8HexDecode(String s) throws Exception { |
|
|
|
public static String utf8HexDecode(String s) throws DecoderException { |
|
|
|
if (s == null) { |
|
|
|
if (s == null) { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
return new String(Hex.decodeHex(s.toCharArray()), StandardCharsets.UTF_8); |
|
|
|
return new String(Hex.decodeHex(s.toCharArray()), StandardCharsets.UTF_8); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Calculates the MD5 digest and returns the value as a 32 character hex string. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param s Data to digest. |
|
|
|
|
|
|
|
* @return MD5 digest as a hex string. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static String md5Hex(String s) { |
|
|
|
|
|
|
|
if (s == null) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
MessageDigest md5 = MessageDigest.getInstance("MD5"); |
|
|
|
|
|
|
|
return new String(Hex.encodeHex(md5.digest(s.getBytes(StandardCharsets.UTF_8)))); |
|
|
|
|
|
|
|
} catch (Exception x) { |
|
|
|
|
|
|
|
throw new RuntimeException(x.getMessage(), x); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Returns the file part of an URL. For instance: |
|
|
|
* Returns the file part of an URL. For instance: |
|
|
|
* <p/> |
|
|
|
* <p/> |
|
|
|