Commit e53e5938 by olly Committed by Oliver Woodman

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.

#minor-release
#exofixit
Issue: #9087
PiperOrigin-RevId: 395274934
parent 66335ab6
...@@ -71,6 +71,9 @@ ...@@ -71,6 +71,9 @@
* RTSP: * RTSP:
* Handle when additional spaces are in SDP's RTPMAP atrribute * Handle when additional spaces are in SDP's RTPMAP atrribute
([#9379](https://github.com/google/ExoPlayer/issues/9379)). ([#9379](https://github.com/google/ExoPlayer/issues/9379)).
* Extractors:
* ID3: Fix issue decoding ID3 tags containing UTF-16 encoded strings
([#9087](https://github.com/google/ExoPlayer/issues/9087)).
### 2.15.0 (2021-08-10) ### 2.15.0 (2021-08-10)
......
...@@ -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