Commit 1bd96fba by olly Committed by Christos Tsilopoulos

ID3: Fix end-of-string detection for UTF-16

The current detection logic checks that the two byte terminator starts
at an even position in the ID3 data, where-as it should check that it
starts at an even position relative to the start of the string.

Issue: #9087
PiperOrigin-RevId: 395274934
parent a1d376fa
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
* Extractors: * Extractors:
* Support TS packets without PTS flag * Support TS packets without PTS flag
([#9294](https://github.com/google/ExoPlayer/issues/9294)). ([#9294](https://github.com/google/ExoPlayer/issues/9294)).
* ID3: Fix issue decoding ID3 tags containing UTF-16 encoded strings
([#9087](https://github.com/google/ExoPlayer/issues/9087)).
* Video: * Video:
* Request smaller decoder input buffers for Dolby Vision. This fixes an * Request smaller decoder input buffers for Dolby Vision. This fixes an
issue that could cause UHD Dolby Vision playbacks to fail on some issue that could cause UHD Dolby Vision playbacks to fail on some
......
...@@ -806,9 +806,9 @@ public final class Id3Decoder extends SimpleMetadataDecoder { ...@@ -806,9 +806,9 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
return terminationPos; return terminationPos;
} }
// Otherwise ensure an even index and look for a second zero byte. // Otherwise ensure an even offset from the start, and look for a second zero byte.
while (terminationPos < data.length - 1) { while (terminationPos < data.length - 1) {
if (terminationPos % 2 == 0 && data[terminationPos + 1] == (byte) 0) { if ((terminationPos - fromIndex) % 2 == 0 && data[terminationPos + 1] == (byte) 0) {
return terminationPos; return terminationPos;
} }
terminationPos = indexOfZeroByte(data, terminationPos + 1); terminationPos = indexOfZeroByte(data, terminationPos + 1);
......
...@@ -38,6 +38,7 @@ public final class Id3DecoderTest { ...@@ -38,6 +38,7 @@ public final class Id3DecoderTest {
@Test @Test
public void decodeTxxxFrame() { public void decodeTxxxFrame() {
// Test UTF-8.
byte[] rawId3 = byte[] rawId3 =
buildSingleFrameTag( buildSingleFrameTag(
"TXXX", "TXXX",
...@@ -53,6 +54,21 @@ public final class Id3DecoderTest { ...@@ -53,6 +54,21 @@ public final class Id3DecoderTest {
assertThat(textInformationFrame.description).isEmpty(); assertThat(textInformationFrame.description).isEmpty();
assertThat(textInformationFrame.value).isEqualTo("mdialog_VINDICO1527664_start"); assertThat(textInformationFrame.value).isEqualTo("mdialog_VINDICO1527664_start");
// Test UTF-16.
rawId3 =
buildSingleFrameTag(
"TXXX",
new byte[] {
1, 0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0,
100, 0, 0
});
metadata = decoder.decode(rawId3, rawId3.length);
assertThat(metadata.length()).isEqualTo(1);
textInformationFrame = (TextInformationFrame) metadata.get(0);
assertThat(textInformationFrame.id).isEqualTo("TXXX");
assertThat(textInformationFrame.description).isEqualTo("Hello World");
assertThat(textInformationFrame.value).isEmpty();
// Test empty. // Test empty.
rawId3 = buildSingleFrameTag("TXXX", new byte[0]); rawId3 = buildSingleFrameTag("TXXX", new byte[0]);
metadata = decoder.decode(rawId3, rawId3.length); metadata = decoder.decode(rawId3, rawId3.length);
...@@ -220,6 +236,43 @@ public final class Id3DecoderTest { ...@@ -220,6 +236,43 @@ public final class Id3DecoderTest {
assertThat(apicFrame.description).isEqualTo("Hello World"); assertThat(apicFrame.description).isEqualTo("Hello World");
assertThat(apicFrame.pictureData).hasLength(10); assertThat(apicFrame.pictureData).hasLength(10);
assertThat(apicFrame.pictureData).isEqualTo(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}); assertThat(apicFrame.pictureData).isEqualTo(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0});
// Test with UTF-16 description at even offset.
rawId3 =
buildSingleFrameTag(
"APIC",
new byte[] {
1, 105, 109, 97, 103, 101, 47, 106, 112, 101, 103, 0, 16, 0, 72, 0, 101, 0, 108, 0,
108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0, 0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 0
});
decoder = new Id3Decoder();
metadata = decoder.decode(rawId3, rawId3.length);
assertThat(metadata.length()).isEqualTo(1);
apicFrame = (ApicFrame) metadata.get(0);
assertThat(apicFrame.mimeType).isEqualTo("image/jpeg");
assertThat(apicFrame.pictureType).isEqualTo(16);
assertThat(apicFrame.description).isEqualTo("Hello World");
assertThat(apicFrame.pictureData).hasLength(10);
assertThat(apicFrame.pictureData).isEqualTo(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0});
// Test with UTF-16 description at odd offset.
rawId3 =
buildSingleFrameTag(
"APIC",
new byte[] {
1, 105, 109, 97, 103, 101, 47, 112, 110, 103, 0, 16, 0, 72, 0, 101, 0, 108, 0, 108, 0,
111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
});
decoder = new Id3Decoder();
metadata = decoder.decode(rawId3, rawId3.length);
assertThat(metadata.length()).isEqualTo(1);
apicFrame = (ApicFrame) metadata.get(0);
assertThat(apicFrame.mimeType).isEqualTo("image/png");
assertThat(apicFrame.pictureType).isEqualTo(16);
assertThat(apicFrame.description).isEqualTo("Hello World");
assertThat(apicFrame.pictureData).hasLength(10);
assertThat(apicFrame.pictureData).isEqualTo(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0});
} }
@Test @Test
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment