GameCult.Networking: write_admitted messageId from embedded Unicode 16.0 tables, not .NET's
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
c4f6e76839
commit
c2d2c1d126
2 changed files with 164 additions and 27 deletions
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Globalization;
|
||||
using MessagePack;
|
||||
|
||||
namespace GameCult.Networking
|
||||
|
|
@ -103,21 +102,13 @@ namespace GameCult.Networking
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The write_admitted messageId rule (write-receipt.md): a Unicode letter or number somewhere, no Default_Ignorable code
|
||||
/// point anywhere, wire bytes that are valid UTF-8, compared raw (never trimmed). Letters and numbers come from the
|
||||
/// runtime's Unicode categories (L*, Nd, Nl, No); a code point it does not assign (U+0378 in every version) has neither.
|
||||
/// .NET has no Default_Ignorable property, so the ranges are embedded from DerivedCoreProperties.txt, Unicode 16.0
|
||||
/// (unchanged since 15.1); the Kotlin, Python and Rust decoders embed the same ranges, TypeScript uses its regex engine's.
|
||||
/// The write_admitted messageId rule (write-receipt.md): a letter (Lu Ll Lt Lm Lo) or number (Nd Nl No) somewhere, no
|
||||
/// Default_Ignorable code point anywhere, as of Unicode 16.0, wire bytes that are valid UTF-8, compared raw (never trimmed).
|
||||
/// The tables are embedded (CultNetUnicodeMessageIdTables.cs, generated by scripts/gen-unicode-messageid-tables.py), not
|
||||
/// .NET's, so the running runtime's Unicode version changes no result; the other four runtimes embed the same tables.
|
||||
/// </summary>
|
||||
internal static class CultNetAdmittedMessageId
|
||||
{
|
||||
private static readonly (int Low, int High)[] DefaultIgnorable =
|
||||
{
|
||||
(0x00AD, 0x00AD), (0x034F, 0x034F), (0x061C, 0x061C), (0x115F, 0x1160), (0x17B4, 0x17B5), (0x180B, 0x180F),
|
||||
(0x200B, 0x200F), (0x202A, 0x202E), (0x2060, 0x206F), (0x3164, 0x3164), (0xFE00, 0xFE0F), (0xFEFF, 0xFEFF),
|
||||
(0xFFA0, 0xFFA0), (0xFFF0, 0xFFF8), (0x1BCA0, 0x1BCA3), (0x1D173, 0x1D17A), (0xE0000, 0xE0FFF),
|
||||
};
|
||||
|
||||
private static readonly System.Text.UTF8Encoding StrictUtf8 = new(false, true);
|
||||
|
||||
/// <summary>Throws unless the frame's top-level <c>messageId</c> is a valid write_admitted id; other keys are left to the serializer.</summary>
|
||||
|
|
@ -148,23 +139,25 @@ namespace GameCult.Networking
|
|||
for (var at = 0; at < id.Length; at += char.IsSurrogatePair(id, at) ? 2 : 1)
|
||||
{
|
||||
var point = char.IsSurrogatePair(id, at) ? char.ConvertToUtf32(id, at) : id[at];
|
||||
if (Array.Exists(DefaultIgnorable, range => point >= range.Low && point <= range.High)) return false;
|
||||
switch (CharUnicodeInfo.GetUnicodeCategory(point))
|
||||
{
|
||||
case UnicodeCategory.UppercaseLetter:
|
||||
case UnicodeCategory.LowercaseLetter:
|
||||
case UnicodeCategory.TitlecaseLetter:
|
||||
case UnicodeCategory.ModifierLetter:
|
||||
case UnicodeCategory.OtherLetter:
|
||||
case UnicodeCategory.DecimalDigitNumber:
|
||||
case UnicodeCategory.LetterNumber:
|
||||
case UnicodeCategory.OtherNumber:
|
||||
hasLetterOrNumber = true;
|
||||
break;
|
||||
}
|
||||
if (InRanges(CultNetUnicodeMessageIdTables.DefaultIgnorable, point)) return false;
|
||||
hasLetterOrNumber |= InRanges(CultNetUnicodeMessageIdTables.LetterOrNumber, point);
|
||||
}
|
||||
|
||||
return hasLetterOrNumber;
|
||||
}
|
||||
|
||||
private static bool InRanges(int[] ranges, int point)
|
||||
{
|
||||
int low = 0, high = ranges.Length / 2 - 1;
|
||||
while (low <= high)
|
||||
{
|
||||
var mid = (low + high) >> 1;
|
||||
if (point < ranges[2 * mid]) high = mid - 1;
|
||||
else if (point > ranges[2 * mid + 1]) low = mid + 1;
|
||||
else return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue