Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f5e0842
Initial plan
Copilot Jan 25, 2026
81ddd69
Add TryGetAscii and TryGetUnicode span-based APIs to IdnMapping
Copilot Jan 25, 2026
a4f93e4
Add tests for TryGetAscii and TryGetUnicode methods
Copilot Jan 25, 2026
511b2c5
Remove unnecessary TryGetAsciiCore/TryGetUnicodeCore indirection
Copilot Jan 25, 2026
5e3facf
Remove GetAsciiCore/GetUnicodeCore indirection, inline directly into …
Copilot Jan 25, 2026
d626cb2
Remove unsafe code from TryGetAscii/TryGetUnicode, use span-based int…
Copilot Jan 25, 2026
a909529
Remove unsafe code, use span-based APIs throughout, fix allocation issue
Copilot Jan 25, 2026
ad00162
Fix potential out-of-bounds access in IsSurrogatePair check
Copilot Jan 25, 2026
1b4eaec
Simplify GetBidiCategory(string) to call span-based overload
Copilot Jan 25, 2026
30f67eb
Remove unused pointer-based interop method definitions
Copilot Jan 26, 2026
1488db9
Address review feedback: simplify code and fix docs
Copilot Jan 26, 2026
5d34496
Use span-based TryGetAscii/TryGetUnicode in DomainNameHelper to avoid…
Copilot Jan 26, 2026
b9f72ff
Address copilot-pull-request-reviewer feedback: add tests with UseStd…
Copilot Jan 26, 2026
bbcb649
Address MihaZupan review feedback: fix test build errors, simplify Ap…
Copilot Jan 26, 2026
165ef82
Address MihaZupan feedback: fix comment casing, add debug assert, use…
Copilot Jan 26, 2026
c753f6b
Remove overlapping buffer tests and document that overlapping is NOT …
Copilot Jan 26, 2026
39fd8ae
Add overlapping buffer check for TryGetAscii and TryGetUnicode, throw…
Copilot Jan 26, 2026
354d564
Simplify overlapping buffer check to use source.Overlaps(destination)…
Copilot Jan 26, 2026
12e1a54
Merge branch 'main' into copilot/add-idnmapping-span-apis-again
MihaZupan Jan 26, 2026
b7952d8
Apply formatting suggestions: add blank lines and braces to if statem…
Copilot Jan 27, 2026
ab4609c
Merge branch 'main' into copilot/add-idnmapping-span-apis-again
stephentoub Jan 28, 2026
50a1b96
Merge branch 'main' into copilot/add-idnmapping-span-apis-again
stephentoub Jan 29, 2026
e3397b3
Fix test failures: skip invalid index/count entries in TryGetAscii_In…
Copilot Jan 29, 2026
15aaef5
Address feedback: add blank line before return, move == 0 check insid…
Copilot Jan 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,33 @@ private static StrongBidiCategory GetBidiCategoryNoBoundsChecks(uint codePoint)
return bidiCategory;
}

internal static StrongBidiCategory GetBidiCategory(ReadOnlySpan<char> s, int index)
{
Debug.Assert(index >= 0 && index < s.Length, "index < s.Length");

// The logic below follows Table 3-5 in the Unicode Standard, Sec. 3.9.
// First char (high surrogate) = 110110wwwwxxxxxx
// Second char (low surrogate) = 110111xxxxxxxxxx

int c = (int)s[index];
if (index < s.Length - 1)
{
int temp1 = c - HIGH_SURROGATE_START; // temp1 = 000000wwwwxxxxxx
if ((uint)temp1 <= HIGH_SURROGATE_RANGE)
{
int temp2 = (int)s[index + 1] - LOW_SURROGATE_START; // temp2 = 000000xxxxxxxxxx
if ((uint)temp2 <= HIGH_SURROGATE_RANGE)
{
// |--------temp1--||-temp2--|
// 00000uuuuuuxxxxxxxxxxxxxxxx (where uuuuu = wwww + 1)
c = (temp1 << 10) + temp2 + UNICODE_PLANE01_START;
}
}
}

return GetBidiCategoryNoBoundsChecks((uint)c);
}

/*
* GetDecimalDigitValue
* ====================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ namespace System.Globalization
{
public sealed partial class IdnMapping
{
private unsafe string IcuGetAsciiCore(string unicodeString, char* unicode, int count)
private unsafe string IcuGetAsciiCore(string? unicodeString, char* unicode, int count)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(unicodeString != null && unicodeString.Length >= count);

uint flags = IcuFlags;
CheckInvalidIdnCharacters(unicode, count, flags, nameof(unicode));
Expand Down Expand Up @@ -51,11 +50,33 @@ private unsafe string IcuGetAsciiCore(string unicodeString, char* unicode, int c
}
}

private unsafe string IcuGetUnicodeCore(string asciiString, char* ascii, int count)
private unsafe bool IcuTryGetAsciiCore(char* unicode, int count, char* destination, int destinationLength, out int charsWritten)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(!GlobalizationMode.UseNls);

uint flags = IcuFlags;
CheckInvalidIdnCharacters(unicode, count, flags, nameof(unicode));

int actualLength = Interop.Globalization.ToAscii(flags, unicode, count, destination, destinationLength);
if (actualLength == 0)
{
throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(unicode));
}
if (actualLength <= destinationLength)
{
charsWritten = actualLength;
return true;
}

charsWritten = 0;
return false;
}

private unsafe string IcuGetUnicodeCore(string? asciiString, char* ascii, int count)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(asciiString != null && asciiString.Length >= count);

uint flags = IcuFlags;
CheckInvalidIdnCharacters(ascii, count, flags, nameof(ascii));
Expand All @@ -76,11 +97,10 @@ private unsafe string IcuGetUnicodeCore(string asciiString, char* ascii, int cou
}
}

private unsafe string IcuGetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength, bool reattempt)
private unsafe string IcuGetUnicodeCore(string? asciiString, char* ascii, int count, uint flags, char* output, int outputLength, bool reattempt)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(asciiString != null && asciiString.Length >= count);

int realLen = Interop.Globalization.ToUnicode(flags, ascii, count, output, outputLength);

Expand All @@ -104,6 +124,29 @@ private unsafe string IcuGetUnicodeCore(string asciiString, char* ascii, int cou
throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(ascii));
}

private unsafe bool IcuTryGetUnicodeCore(char* ascii, int count, char* destination, int destinationLength, out int charsWritten)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(!GlobalizationMode.UseNls);

uint flags = IcuFlags;
CheckInvalidIdnCharacters(ascii, count, flags, nameof(ascii));

int actualLength = Interop.Globalization.ToUnicode(flags, ascii, count, destination, destinationLength);
if (actualLength == 0)
{
throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(ascii));
}
if (actualLength <= destinationLength)
{
charsWritten = actualLength;
return true;
}

charsWritten = 0;
return false;
}

private uint IcuFlags
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ namespace System.Globalization
{
public sealed partial class IdnMapping
{
private unsafe string NlsGetAsciiCore(string unicodeString, char* unicode, int count)
private unsafe string NlsGetAsciiCore(string? unicodeString, char* unicode, int count)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(unicodeString != null && unicodeString.Length >= count);

uint flags = NlsFlags;

Expand Down Expand Up @@ -41,11 +40,10 @@ private unsafe string NlsGetAsciiCore(string unicodeString, char* unicode, int c
}
}

private static unsafe string NlsGetAsciiCore(string unicodeString, char* unicode, int count, uint flags, char* output, int outputLength)
private static unsafe string NlsGetAsciiCore(string? unicodeString, char* unicode, int count, uint flags, char* output, int outputLength)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(unicodeString != null && unicodeString.Length >= count);

int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, output, outputLength);
if (length == 0)
Expand All @@ -56,11 +54,41 @@ private static unsafe string NlsGetAsciiCore(string unicodeString, char* unicode
return GetStringForOutput(unicodeString, unicode, count, output, length);
}

private unsafe string NlsGetUnicodeCore(string asciiString, char* ascii, int count)
private unsafe bool NlsTryGetAsciiCore(char* unicode, int count, char* destination, int destinationLength, out int charsWritten)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(GlobalizationMode.UseNls);

uint flags = NlsFlags;

// Determine the required length
int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, null, 0);
if (length == 0)
{
ThrowForZeroLength(unicode: true);
}

if (length > destinationLength)
{
charsWritten = 0;
return false;
}

// Do the conversion
int actualLength = Interop.Normaliz.IdnToAscii(flags, unicode, count, destination, destinationLength);
if (actualLength == 0)
{
ThrowForZeroLength(unicode: true);
}

charsWritten = actualLength;
return true;
}

private unsafe string NlsGetUnicodeCore(string? asciiString, char* ascii, int count)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(asciiString != null && asciiString.Length >= count);

uint flags = NlsFlags;

Expand Down Expand Up @@ -88,11 +116,10 @@ private unsafe string NlsGetUnicodeCore(string asciiString, char* ascii, int cou
}
}

private static unsafe string NlsGetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength)
private static unsafe string NlsGetUnicodeCore(string? asciiString, char* ascii, int count, uint flags, char* output, int outputLength)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(asciiString != null && asciiString.Length >= count);

int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, output, outputLength);
if (length == 0)
Expand All @@ -103,6 +130,37 @@ private static unsafe string NlsGetUnicodeCore(string asciiString, char* ascii,
return GetStringForOutput(asciiString, ascii, count, output, length);
}

private unsafe bool NlsTryGetUnicodeCore(char* ascii, int count, char* destination, int destinationLength, out int charsWritten)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(GlobalizationMode.UseNls);

uint flags = NlsFlags;

// Determine the required length
int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, null, 0);
if (length == 0)
{
ThrowForZeroLength(unicode: false);
}

if (length > destinationLength)
{
charsWritten = 0;
return false;
}

// Do the conversion
int actualLength = Interop.Normaliz.IdnToUnicode(flags, ascii, count, destination, destinationLength);
if (actualLength == 0)
{
ThrowForZeroLength(unicode: false);
}

charsWritten = actualLength;
return true;
}

private uint NlsFlags
{
get
Expand Down
Loading
Loading