Remove impossible UnsupportedEncodingException from Id3Decoder

The list of charsets is already hard-coded, and using `Charset` types
ensures they will all be present at run-time, hence we will never
encounter an 'unsupported' charset.

PiperOrigin-RevId: 491324466
(cherry picked from commit 5292e408a6fd000c1a125519e22a7c18460eed59)
This commit is contained in:
ibaker 2022-11-28 14:15:03 +00:00 committed by christosts
parent 26f5e9b83c
commit 289f0cf00b

View File

@ -26,9 +26,10 @@ import androidx.media3.common.util.Util;
import androidx.media3.extractor.metadata.MetadataInputBuffer; import androidx.media3.extractor.metadata.MetadataInputBuffer;
import androidx.media3.extractor.metadata.SimpleMetadataDecoder; import androidx.media3.extractor.metadata.SimpleMetadataDecoder;
import com.google.common.base.Ascii; import com.google.common.base.Ascii;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -436,30 +437,25 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
+ frameSize); + frameSize);
} }
return frame; return frame;
} catch (UnsupportedEncodingException e) {
Log.w(TAG, "Unsupported character encoding");
return null;
} finally { } finally {
id3Data.setPosition(nextFramePosition); id3Data.setPosition(nextFramePosition);
} }
} }
@Nullable @Nullable
private static TextInformationFrame decodeTxxxFrame(ParsableByteArray id3Data, int frameSize) private static TextInformationFrame decodeTxxxFrame(ParsableByteArray id3Data, int frameSize) {
throws UnsupportedEncodingException {
if (frameSize < 1) { if (frameSize < 1) {
// Frame is malformed. // Frame is malformed.
return null; return null;
} }
int encoding = id3Data.readUnsignedByte(); int encoding = id3Data.readUnsignedByte();
String charset = getCharsetName(encoding);
byte[] data = new byte[frameSize - 1]; byte[] data = new byte[frameSize - 1];
id3Data.readBytes(data, 0, frameSize - 1); id3Data.readBytes(data, 0, frameSize - 1);
int descriptionEndIndex = indexOfTerminator(data, 0, encoding); int descriptionEndIndex = indexOfTerminator(data, 0, encoding);
String description = new String(data, 0, descriptionEndIndex, charset); String description = new String(data, 0, descriptionEndIndex, getCharset(encoding));
ImmutableList<String> values = ImmutableList<String> values =
decodeTextInformationFrameValues( decodeTextInformationFrameValues(
@ -469,7 +465,7 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
@Nullable @Nullable
private static TextInformationFrame decodeTextInformationFrame( private static TextInformationFrame decodeTextInformationFrame(
ParsableByteArray id3Data, int frameSize, String id) throws UnsupportedEncodingException { ParsableByteArray id3Data, int frameSize, String id) {
if (frameSize < 1) { if (frameSize < 1) {
// Frame is malformed. // Frame is malformed.
return null; return null;
@ -485,17 +481,17 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
} }
private static ImmutableList<String> decodeTextInformationFrameValues( private static ImmutableList<String> decodeTextInformationFrameValues(
byte[] data, final int encoding, final int index) throws UnsupportedEncodingException { byte[] data, final int encoding, final int index) {
if (index >= data.length) { if (index >= data.length) {
return ImmutableList.of(""); return ImmutableList.of("");
} }
ImmutableList.Builder<String> values = ImmutableList.builder(); ImmutableList.Builder<String> values = ImmutableList.builder();
String charset = getCharsetName(encoding);
int valueStartIndex = index; int valueStartIndex = index;
int valueEndIndex = indexOfTerminator(data, valueStartIndex, encoding); int valueEndIndex = indexOfTerminator(data, valueStartIndex, encoding);
while (valueStartIndex < valueEndIndex) { while (valueStartIndex < valueEndIndex) {
String value = new String(data, valueStartIndex, valueEndIndex - valueStartIndex, charset); String value =
new String(data, valueStartIndex, valueEndIndex - valueStartIndex, getCharset(encoding));
values.add(value); values.add(value);
valueStartIndex = valueEndIndex + delimiterLength(encoding); valueStartIndex = valueEndIndex + delimiterLength(encoding);
@ -507,47 +503,44 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
} }
@Nullable @Nullable
private static UrlLinkFrame decodeWxxxFrame(ParsableByteArray id3Data, int frameSize) private static UrlLinkFrame decodeWxxxFrame(ParsableByteArray id3Data, int frameSize) {
throws UnsupportedEncodingException {
if (frameSize < 1) { if (frameSize < 1) {
// Frame is malformed. // Frame is malformed.
return null; return null;
} }
int encoding = id3Data.readUnsignedByte(); int encoding = id3Data.readUnsignedByte();
String charset = getCharsetName(encoding);
byte[] data = new byte[frameSize - 1]; byte[] data = new byte[frameSize - 1];
id3Data.readBytes(data, 0, frameSize - 1); id3Data.readBytes(data, 0, frameSize - 1);
int descriptionEndIndex = indexOfTerminator(data, 0, encoding); int descriptionEndIndex = indexOfTerminator(data, 0, encoding);
String description = new String(data, 0, descriptionEndIndex, charset); String description = new String(data, 0, descriptionEndIndex, getCharset(encoding));
int urlStartIndex = descriptionEndIndex + delimiterLength(encoding); int urlStartIndex = descriptionEndIndex + delimiterLength(encoding);
int urlEndIndex = indexOfZeroByte(data, urlStartIndex); int urlEndIndex = indexOfZeroByte(data, urlStartIndex);
String url = decodeStringIfValid(data, urlStartIndex, urlEndIndex, "ISO-8859-1"); String url = decodeStringIfValid(data, urlStartIndex, urlEndIndex, Charsets.ISO_8859_1);
return new UrlLinkFrame("WXXX", description, url); return new UrlLinkFrame("WXXX", description, url);
} }
private static UrlLinkFrame decodeUrlLinkFrame( private static UrlLinkFrame decodeUrlLinkFrame(
ParsableByteArray id3Data, int frameSize, String id) throws UnsupportedEncodingException { ParsableByteArray id3Data, int frameSize, String id) {
byte[] data = new byte[frameSize]; byte[] data = new byte[frameSize];
id3Data.readBytes(data, 0, frameSize); id3Data.readBytes(data, 0, frameSize);
int urlEndIndex = indexOfZeroByte(data, 0); int urlEndIndex = indexOfZeroByte(data, 0);
String url = new String(data, 0, urlEndIndex, "ISO-8859-1"); String url = new String(data, 0, urlEndIndex, Charsets.ISO_8859_1);
return new UrlLinkFrame(id, null, url); return new UrlLinkFrame(id, null, url);
} }
private static PrivFrame decodePrivFrame(ParsableByteArray id3Data, int frameSize) private static PrivFrame decodePrivFrame(ParsableByteArray id3Data, int frameSize) {
throws UnsupportedEncodingException {
byte[] data = new byte[frameSize]; byte[] data = new byte[frameSize];
id3Data.readBytes(data, 0, frameSize); id3Data.readBytes(data, 0, frameSize);
int ownerEndIndex = indexOfZeroByte(data, 0); int ownerEndIndex = indexOfZeroByte(data, 0);
String owner = new String(data, 0, ownerEndIndex, "ISO-8859-1"); String owner = new String(data, 0, ownerEndIndex, Charsets.ISO_8859_1);
int privateDataStartIndex = ownerEndIndex + 1; int privateDataStartIndex = ownerEndIndex + 1;
byte[] privateData = copyOfRangeIfValid(data, privateDataStartIndex, data.length); byte[] privateData = copyOfRangeIfValid(data, privateDataStartIndex, data.length);
@ -555,16 +548,15 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
return new PrivFrame(owner, privateData); return new PrivFrame(owner, privateData);
} }
private static GeobFrame decodeGeobFrame(ParsableByteArray id3Data, int frameSize) private static GeobFrame decodeGeobFrame(ParsableByteArray id3Data, int frameSize) {
throws UnsupportedEncodingException {
int encoding = id3Data.readUnsignedByte(); int encoding = id3Data.readUnsignedByte();
String charset = getCharsetName(encoding); Charset charset = getCharset(encoding);
byte[] data = new byte[frameSize - 1]; byte[] data = new byte[frameSize - 1];
id3Data.readBytes(data, 0, frameSize - 1); id3Data.readBytes(data, 0, frameSize - 1);
int mimeTypeEndIndex = indexOfZeroByte(data, 0); int mimeTypeEndIndex = indexOfZeroByte(data, 0);
String mimeType = new String(data, 0, mimeTypeEndIndex, "ISO-8859-1"); String mimeType = new String(data, 0, mimeTypeEndIndex, Charsets.ISO_8859_1);
int filenameStartIndex = mimeTypeEndIndex + 1; int filenameStartIndex = mimeTypeEndIndex + 1;
int filenameEndIndex = indexOfTerminator(data, filenameStartIndex, encoding); int filenameEndIndex = indexOfTerminator(data, filenameStartIndex, encoding);
@ -582,10 +574,9 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
} }
private static ApicFrame decodeApicFrame( private static ApicFrame decodeApicFrame(
ParsableByteArray id3Data, int frameSize, int majorVersion) ParsableByteArray id3Data, int frameSize, int majorVersion) {
throws UnsupportedEncodingException {
int encoding = id3Data.readUnsignedByte(); int encoding = id3Data.readUnsignedByte();
String charset = getCharsetName(encoding); Charset charset = getCharset(encoding);
byte[] data = new byte[frameSize - 1]; byte[] data = new byte[frameSize - 1];
id3Data.readBytes(data, 0, frameSize - 1); id3Data.readBytes(data, 0, frameSize - 1);
@ -594,13 +585,13 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
int mimeTypeEndIndex; int mimeTypeEndIndex;
if (majorVersion == 2) { if (majorVersion == 2) {
mimeTypeEndIndex = 2; mimeTypeEndIndex = 2;
mimeType = "image/" + Ascii.toLowerCase(new String(data, 0, 3, "ISO-8859-1")); mimeType = "image/" + Ascii.toLowerCase(new String(data, 0, 3, Charsets.ISO_8859_1));
if ("image/jpg".equals(mimeType)) { if ("image/jpg".equals(mimeType)) {
mimeType = "image/jpeg"; mimeType = "image/jpeg";
} }
} else { } else {
mimeTypeEndIndex = indexOfZeroByte(data, 0); mimeTypeEndIndex = indexOfZeroByte(data, 0);
mimeType = Ascii.toLowerCase(new String(data, 0, mimeTypeEndIndex, "ISO-8859-1")); mimeType = Ascii.toLowerCase(new String(data, 0, mimeTypeEndIndex, Charsets.ISO_8859_1));
if (mimeType.indexOf('/') == -1) { if (mimeType.indexOf('/') == -1) {
mimeType = "image/" + mimeType; mimeType = "image/" + mimeType;
} }
@ -621,15 +612,14 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
} }
@Nullable @Nullable
private static CommentFrame decodeCommentFrame(ParsableByteArray id3Data, int frameSize) private static CommentFrame decodeCommentFrame(ParsableByteArray id3Data, int frameSize) {
throws UnsupportedEncodingException {
if (frameSize < 4) { if (frameSize < 4) {
// Frame is malformed. // Frame is malformed.
return null; return null;
} }
int encoding = id3Data.readUnsignedByte(); int encoding = id3Data.readUnsignedByte();
String charset = getCharsetName(encoding); Charset charset = getCharset(encoding);
byte[] data = new byte[3]; byte[] data = new byte[3];
id3Data.readBytes(data, 0, 3); id3Data.readBytes(data, 0, 3);
@ -654,13 +644,15 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
int majorVersion, int majorVersion,
boolean unsignedIntFrameSizeHack, boolean unsignedIntFrameSizeHack,
int frameHeaderSize, int frameHeaderSize,
@Nullable FramePredicate framePredicate) @Nullable FramePredicate framePredicate) {
throws UnsupportedEncodingException {
int framePosition = id3Data.getPosition(); int framePosition = id3Data.getPosition();
int chapterIdEndIndex = indexOfZeroByte(id3Data.getData(), framePosition); int chapterIdEndIndex = indexOfZeroByte(id3Data.getData(), framePosition);
String chapterId = String chapterId =
new String( new String(
id3Data.getData(), framePosition, chapterIdEndIndex - framePosition, "ISO-8859-1"); id3Data.getData(),
framePosition,
chapterIdEndIndex - framePosition,
Charsets.ISO_8859_1);
id3Data.setPosition(chapterIdEndIndex + 1); id3Data.setPosition(chapterIdEndIndex + 1);
int startTime = id3Data.readInt(); int startTime = id3Data.readInt();
@ -695,13 +687,15 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
int majorVersion, int majorVersion,
boolean unsignedIntFrameSizeHack, boolean unsignedIntFrameSizeHack,
int frameHeaderSize, int frameHeaderSize,
@Nullable FramePredicate framePredicate) @Nullable FramePredicate framePredicate) {
throws UnsupportedEncodingException {
int framePosition = id3Data.getPosition(); int framePosition = id3Data.getPosition();
int elementIdEndIndex = indexOfZeroByte(id3Data.getData(), framePosition); int elementIdEndIndex = indexOfZeroByte(id3Data.getData(), framePosition);
String elementId = String elementId =
new String( new String(
id3Data.getData(), framePosition, elementIdEndIndex - framePosition, "ISO-8859-1"); id3Data.getData(),
framePosition,
elementIdEndIndex - framePosition,
Charsets.ISO_8859_1);
id3Data.setPosition(elementIdEndIndex + 1); id3Data.setPosition(elementIdEndIndex + 1);
int ctocFlags = id3Data.readUnsignedByte(); int ctocFlags = id3Data.readUnsignedByte();
@ -713,7 +707,8 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
for (int i = 0; i < childCount; i++) { for (int i = 0; i < childCount; i++) {
int startIndex = id3Data.getPosition(); int startIndex = id3Data.getPosition();
int endIndex = indexOfZeroByte(id3Data.getData(), startIndex); int endIndex = indexOfZeroByte(id3Data.getData(), startIndex);
children[i] = new String(id3Data.getData(), startIndex, endIndex - startIndex, "ISO-8859-1"); children[i] =
new String(id3Data.getData(), startIndex, endIndex - startIndex, Charsets.ISO_8859_1);
id3Data.setPosition(endIndex + 1); id3Data.setPosition(endIndex + 1);
} }
@ -792,23 +787,18 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
return length; return length;
} }
/** /** Maps encoding byte from ID3v2 frame to a {@link Charset}. */
* Maps encoding byte from ID3v2 frame to a Charset. private static Charset getCharset(int encodingByte) {
*
* @param encodingByte The value of encoding byte from ID3v2 frame.
* @return Charset name.
*/
private static String getCharsetName(int encodingByte) {
switch (encodingByte) { switch (encodingByte) {
case ID3_TEXT_ENCODING_UTF_16: case ID3_TEXT_ENCODING_UTF_16:
return "UTF-16"; return Charsets.UTF_16;
case ID3_TEXT_ENCODING_UTF_16BE: case ID3_TEXT_ENCODING_UTF_16BE:
return "UTF-16BE"; return Charsets.UTF_16BE;
case ID3_TEXT_ENCODING_UTF_8: case ID3_TEXT_ENCODING_UTF_8:
return "UTF-8"; return Charsets.UTF_8;
case ID3_TEXT_ENCODING_ISO_8859_1: case ID3_TEXT_ENCODING_ISO_8859_1:
default: default:
return "ISO-8859-1"; return Charsets.ISO_8859_1;
} }
} }
@ -871,21 +861,19 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
/** /**
* Returns a string obtained by decoding the specified range of {@code data} using the specified * Returns a string obtained by decoding the specified range of {@code data} using the specified
* {@code charsetName}. An empty string is returned if the range is invalid. * {@code charset}. An empty string is returned if the range is invalid.
* *
* @param data The array from which to decode the string. * @param data The array from which to decode the string.
* @param from The start of the range. * @param from The start of the range.
* @param to The end of the range (exclusive). * @param to The end of the range (exclusive).
* @param charsetName The name of the Charset to use. * @param charset The {@link Charset} to use.
* @return The decoded string, or an empty string if the range is invalid. * @return The decoded string, or an empty string if the range is invalid.
* @throws UnsupportedEncodingException If the Charset is not supported.
*/ */
private static String decodeStringIfValid(byte[] data, int from, int to, String charsetName) private static String decodeStringIfValid(byte[] data, int from, int to, Charset charset) {
throws UnsupportedEncodingException {
if (to <= from || to > data.length) { if (to <= from || to > data.length) {
return ""; return "";
} }
return new String(data, from, to - from, charsetName); return new String(data, from, to - from, charset);
} }
private static final class Id3Header { private static final class Id3Header {