Skip to content

Commit

Permalink
fix: Fix track decoding
Browse files Browse the repository at this point in the history
angelobreuer committed Mar 2, 2024
1 parent 7423934 commit baeb0a4
Showing 2 changed files with 101 additions and 3 deletions.
103 changes: 101 additions & 2 deletions src/Lavalink4NET.Abstractions/Tracks/LavalinkTrackDecoder.cs
Original file line number Diff line number Diff line change
@@ -3,7 +3,6 @@
using System;
using System.Buffers.Binary;
using System.Diagnostics.CodeAnalysis;
using System.Text;

internal ref struct LavalinkTrackDecoder
{
@@ -124,7 +123,107 @@ public bool TryReadString([MaybeNullWhen(false)] out string value)
var stringBuffer = Buffer[..length];
Buffer = Buffer[length..];

value = Encoding.UTF8.GetString(stringBuffer);
value = ReadModifiedUtf8(stringBuffer);
return true;
}

private static string ReadModifiedUtf8(ReadOnlySpan<byte> value)
{
// Ported from https://android.googlesource.com/platform/prebuilts/fullsdk/sources/android-29/+/refs/heads/androidx-wear-release/java/io/DataInputStream.java

Span<char> buffer = value.Length < 256
? stackalloc char[256]
: GC.AllocateUninitializedArray<char>(value.Length * 2);

var length = value.Length;
var count = 0;
var charactersWritten = 0;

// Fast-read all ASCII characters
while (!value.IsEmpty)
{
var character = value[0];

if (character > 127)
{
break;
}

count++;
value = value[1..];
buffer[charactersWritten++] = (char)character;
}

while (!value.IsEmpty)
{
var character = value[0];

switch (character >> 4)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
// 0xxxxxxx
count++;
buffer[charactersWritten++] = (char)character;
value = value[1..];
break;

case 12:
case 13:
// 110x xxxx 10xx xxxx
count += 2;

if (count > length)
{
throw new InvalidDataException("Found partial character at end.");
}

var additionalCharacter = value[1];

if ((additionalCharacter & 0xC0) != 0x80)
{
throw new InvalidDataException($"malformed input around byte {count}");
}

buffer[charactersWritten++] = (char)(((character & 0x1F) << 6) | (additionalCharacter & 0x3F));
value = value[2..];

break;

case 14:
// 1110 xxxx 10xx xxxx 10xx xxxx
count += 3;

if (count > length)
{
throw new InvalidDataException("Found malformed input due to partial character at end");
}

var secondCharacter = (int)value[1];
var thirdCharacter = (int)value[2];

if (((secondCharacter & 0xC0) != 0x80) || ((thirdCharacter & 0xC0) != 0x80))
{
throw new InvalidDataException($"Found malformed input around byte {count - 1}");
}

buffer[charactersWritten++] = (char)(((character & 0x0F) << 12) | ((secondCharacter & 0x3F) << 6) | ((thirdCharacter & 0x3F) << 0));
value = value[3..];

break;

default:
// 10xx xxxx, 1111 xxxx
throw new InvalidDataException($"Found malformed input around byte {count}");
}
}

return buffer[..charactersWritten].ToString();
}
}
Original file line number Diff line number Diff line change
@@ -26,7 +26,6 @@ public void TestTrackDecodeEncodeRoundtripV2(string trackIdentifier)
}

[Theory]
[InlineData("QAAA2AMANUNvenkgYW5pbWFsIGNyb3NzaW5nIG11c2ljIHRoYXQgY3VyZSBteSBoZWFkYWNoZXPwn4y/AAtUZW5kbyBGYXJtcwAAAAAAP9uoAAs4VGJMdUJPQ2xTZwABACtodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PThUYkx1Qk9DbFNnAQA6aHR0cHM6Ly9pLnl0aW1nLmNvbS92aV93ZWJwLzhUYkx1Qk9DbFNnL21heHJlc2RlZmF1bHQud2VicAAAB3lvdXR1YmUAAAAAAAKYtw==")]
[InlineData("QAAAjgMAJFZhbmNlIEpveSAtICdSaXB0aWRlJyBPZmZpY2lhbCBWaWRlbwAObXVzaHJvb212aWRlb3MAAAAAAAMgyAALdUpfMUhNQUdiNGsAAQAraHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj11Sl8xSE1BR2I0awAAAAd5b3V0dWJlAAAAAAAAAAA=")]
[InlineData("QAAAjwMAK1JpdGEgT3JhIC0gWW91ciBTb25nIChPZmZpY2lhbCBMeXJpYyBWaWRlbykACFJpdGEgT3JhAAAAAAACwwgAC2k5NU5sYjdraVBvAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9aTk1TmxiN2tpUG8AAAAHeW91dHViZQAAAAAAAAAA")]
[InlineData("QAAAmgMAMkx1a2FzIEdyYWhhbSAtIExvdmUgU29tZW9uZSBbT0ZGSUNJQUwgTVVTSUMgVklERU9dAAxMdWthcyBHcmFoYW0AAAAAAAOhsAALZE40NHhwSGpOeEUAAQAraHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1kTjQ0eHBIak54RQAAAAd5b3V0dWJlAAAAAAAAAAA=")]

0 comments on commit baeb0a4

Please sign in to comment.