summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Globalization/IdnMapping.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Globalization/IdnMapping.cs')
-rw-r--r--src/mscorlib/src/System/Globalization/IdnMapping.cs929
1 files changed, 320 insertions, 609 deletions
diff --git a/src/mscorlib/src/System/Globalization/IdnMapping.cs b/src/mscorlib/src/System/Globalization/IdnMapping.cs
index bf75f5be3c..4320e3abf5 100644
--- a/src/mscorlib/src/System/Globalization/IdnMapping.cs
+++ b/src/mscorlib/src/System/Globalization/IdnMapping.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-//
// This file contains the IDN functions and implementation.
//
// This allows encoding of non-ASCII domain names in a "punycode" form,
@@ -24,69 +23,18 @@
// RFC 3490 - Internationalizing Domain Names in Applications (IDNA)
// RFC 3491 - Nameprep: A Stringprep Profile for Internationalized Domain Names (IDN)
// RFC 3492 - Punycode: A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA)
-//
-/*
-
-The punycode implementation is based on the sample code in RFC 3492
-
-Copyright (C) The Internet Society (2003). All Rights Reserved.
-
-This document and translations of it may be copied and furnished to
-others, and derivative works that comment on or otherwise explain it
-or assist in its implementation may be prepared, copied, published
-and distributed, in whole or in part, without restriction of any
-kind, provided that the above copyright notice and this paragraph are
-included on all such copies and derivative works. However, this
-document itself may not be modified in any way, such as by removing
-the copyright notice or references to the Internet Society or other
-Internet organizations, except as needed for the purpose of
-developing Internet standards in which case the procedures for
-copyrights defined in the Internet Standards process must be
-followed, or as required to translate it into languages other than
-English.
-
-The limited permissions granted above are perpetual and will not be
-revoked by the Internet Society or its successors or assigns.
-
-This document and the information contained herein is provided on an
-"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
-TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
-BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
-HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
-MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-*/
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using System.Text;
namespace System.Globalization
{
- using System;
- using System.Security;
- using System.Globalization;
- using System.Text;
- using System.Runtime.Versioning;
- using System.Runtime.InteropServices;
- using System.Diagnostics;
- using System.Diagnostics.Contracts;
-
// IdnMapping class used to map names to Punycode
-
- public sealed class IdnMapping
+ public sealed partial class IdnMapping
{
- // Legal name lengths for domain names
- const int M_labelLimit = 63; // Not including dots
- const int M_defaultNameLimit = 255; // Including dots
-
- // IDNA prefix
- const String M_strAcePrefix = "xn--";
-
- // Legal "dot" seperators (i.e: . in www.microsoft.com)
- static char[] M_Dots =
- {
- '.', '\u3002', '\uFF0E', '\uFF61'
- };
-
- bool m_bAllowUnassigned;
- bool m_bUseStd3AsciiRules;
+ private bool _allowUnassigned;
+ private bool _useStd3AsciiRules;
public IdnMapping()
{
@@ -94,282 +42,192 @@ namespace System.Globalization
public bool AllowUnassigned
{
- get
- {
- return this.m_bAllowUnassigned;
- }
-
- set
- {
- this.m_bAllowUnassigned = value;
- }
+ get { return _allowUnassigned; }
+ set { _allowUnassigned = value; }
}
public bool UseStd3AsciiRules
{
- get
- {
- return this.m_bUseStd3AsciiRules;
- }
-
- set
- {
- this.m_bUseStd3AsciiRules = value;
- }
+ get { return _useStd3AsciiRules; }
+ set { _useStd3AsciiRules = value; }
}
// Gets ASCII (Punycode) version of the string
- public String GetAscii(String unicode)
+ public string GetAscii(string unicode)
{
return GetAscii(unicode, 0);
}
- public String GetAscii(String unicode, int index)
+ public string GetAscii(string unicode, int index)
{
- if (unicode==null) throw new ArgumentNullException(nameof(unicode));
+ if (unicode == null)
+ throw new ArgumentNullException(nameof(unicode));
Contract.EndContractBlock();
return GetAscii(unicode, index, unicode.Length - index);
}
- public string GetAscii(String unicode, int index, int count)
+ public string GetAscii(string unicode, int index, int count)
{
- if (unicode == null) throw new ArgumentNullException(nameof(unicode));
+ if (unicode == null)
+ throw new ArgumentNullException(nameof(unicode));
if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index < 0) ? nameof(index) : nameof(count),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException((index < 0) ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
if (index > unicode.Length)
- throw new ArgumentOutOfRangeException(nameof(index),
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
if (index > unicode.Length - count)
- throw new ArgumentOutOfRangeException(nameof(unicode),
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
+ throw new ArgumentOutOfRangeException(nameof(unicode), SR.ArgumentOutOfRange_IndexCountBuffer);
Contract.EndContractBlock();
- // We're only using part of the string
- unicode = unicode.Substring(index, count);
-
- if (Environment.IsWindows8OrAbove)
- {
- return GetAsciiUsingOS(unicode);
- }
-
- // Check for ASCII only string, which will be unchanged
- if (ValidateStd3AndAscii(unicode, UseStd3AsciiRules, true))
- {
- return unicode;
- }
-
- // Cannot be null terminated (normalization won't help us with this one, and
- // may have returned false before checking the whole string above)
- Debug.Assert(unicode.Length >= 1, "[IdnMapping.GetAscii]Expected 0 length strings to fail before now.");
- if (unicode[unicode.Length - 1] <= 0x1f)
- {
- throw new ArgumentException(
- Environment.GetResourceString("Argument_InvalidCharSequence", unicode.Length-1 ),
- nameof(unicode));
- }
-
- // Have to correctly IDNA normalize the string and Unassigned flags
- bool bHasLastDot = (unicode.Length > 0) && IsDot(unicode[unicode.Length - 1]);
- unicode = unicode.Normalize((NormalizationForm)(m_bAllowUnassigned ?
- ExtendedNormalizationForms.FormIdna : ExtendedNormalizationForms.FormIdnaDisallowUnassigned));
-
- // Make sure we didn't normalize away something after a last dot
- if ((!bHasLastDot) && unicode.Length > 0 && IsDot(unicode[unicode.Length - 1]))
- {
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(unicode));
- }
-
- // May need to check Std3 rules again for non-ascii
- if (UseStd3AsciiRules)
+ if (count == 0)
{
- ValidateStd3AndAscii(unicode, true, false);
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode));
}
-
- // Go ahead and encode it
- return punycode_encode(unicode);
- }
-
-
- private String GetAsciiUsingOS(String unicode)
- {
- if (unicode.Length == 0)
- {
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(unicode));
- }
-
- if (unicode[unicode.Length - 1] == 0)
+ if (unicode[index + count - 1] == 0)
{
- throw new ArgumentException(
- Environment.GetResourceString("Argument_InvalidCharSequence", unicode.Length - 1),
- nameof(unicode));
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidCharSequence, index + count - 1), nameof(unicode));
}
-
- uint flags = (uint) ((AllowUnassigned ? IDN_ALLOW_UNASSIGNED : 0) | (UseStd3AsciiRules ? IDN_USE_STD3_ASCII_RULES : 0));
- int length = IdnToAscii(flags, unicode, unicode.Length, null, 0);
- int lastError;
-
- if (length == 0)
+ if (GlobalizationMode.Invariant)
{
- lastError = Marshal.GetLastWin32Error();
- if (lastError == ERROR_INVALID_NAME)
- {
- throw new ArgumentException(Environment.GetResourceString("Argument_IdnIllegalName"), nameof(unicode));
- }
-
- throw new ArgumentException(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex"), nameof(unicode));
+ return GetAsciiInvariant(unicode, index, count);
}
- char [] output = new char[length];
-
- length = IdnToAscii(flags, unicode, unicode.Length, output, length);
- if (length == 0)
+ unsafe
{
- lastError = Marshal.GetLastWin32Error();
- if (lastError == ERROR_INVALID_NAME)
+ fixed (char* pUnicode = unicode)
{
- throw new ArgumentException(Environment.GetResourceString("Argument_IdnIllegalName"), nameof(unicode));
+ return GetAsciiCore(pUnicode + index, count);
}
-
- throw new ArgumentException(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex"), nameof(unicode));
}
-
- return new String(output, 0, length);
}
// Gets Unicode version of the string. Normalized and limited to IDNA characters.
- public String GetUnicode(String ascii)
+ public string GetUnicode(string ascii)
{
return GetUnicode(ascii, 0);
}
- public String GetUnicode(String ascii, int index)
+ public string GetUnicode(string ascii, int index)
{
- if (ascii==null) throw new ArgumentNullException(nameof(ascii));
+ if (ascii == null)
+ throw new ArgumentNullException(nameof(ascii));
Contract.EndContractBlock();
return GetUnicode(ascii, index, ascii.Length - index);
}
- public String GetUnicode(String ascii, int index, int count)
+ public string GetUnicode(string ascii, int index, int count)
{
- if (ascii==null) throw new ArgumentNullException(nameof(ascii));
+ if (ascii == null)
+ throw new ArgumentNullException(nameof(ascii));
if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index < 0) ? nameof(index) : nameof(count),
- Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException((index < 0) ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
if (index > ascii.Length)
- throw new ArgumentOutOfRangeException("byteIndex",
- Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
if (index > ascii.Length - count)
- throw new ArgumentOutOfRangeException(nameof(ascii),
- Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
+ throw new ArgumentOutOfRangeException(nameof(ascii), SR.ArgumentOutOfRange_IndexCountBuffer);
// This is a case (i.e. explicitly null-terminated input) where behavior in .NET and Win32 intentionally differ.
// The .NET APIs should (and did in v4.0 and earlier) throw an ArgumentException on input that includes a terminating null.
// The Win32 APIs fail on an embedded null, but not on a terminating null.
if (count > 0 && ascii[index + count - 1] == (char)0)
- throw new ArgumentException(Environment.GetResourceString("Argument_IdnBadPunycode"),
- nameof(ascii));
+ throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii));
Contract.EndContractBlock();
- // We're only using part of the string
- ascii = ascii.Substring(index, count);
-
- if (Environment.IsWindows8OrAbove)
+ if (GlobalizationMode.Invariant)
{
- return GetUnicodeUsingOS(ascii);
+ return GetUnicodeInvariant(ascii, index, count);
}
- // Convert Punycode to Unicode
- String strUnicode = punycode_decode(ascii);
+ unsafe
+ {
+ fixed (char* pAscii = ascii)
+ {
+ return GetUnicodeCore(pAscii + index, count);
+ }
+ }
+ }
- // Output name MUST obey IDNA rules & round trip (casing differences are allowed)
- if (!ascii.Equals(GetAscii(strUnicode), StringComparison.OrdinalIgnoreCase))
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnIllegalName"), nameof(ascii));
+ public override bool Equals(object obj)
+ {
+ IdnMapping that = obj as IdnMapping;
+ return
+ that != null &&
+ _allowUnassigned == that._allowUnassigned &&
+ _useStd3AsciiRules == that._useStd3AsciiRules;
+ }
- return strUnicode;
+ public override int GetHashCode()
+ {
+ return (_allowUnassigned ? 100 : 200) + (_useStd3AsciiRules ? 1000 : 2000);
}
-
- private string GetUnicodeUsingOS(string ascii)
+ //
+ // Invariant implementation
+ //
+
+ private const char c_delimiter = '-';
+ private const string c_strAcePrefix = "xn--";
+ private const int c_labelLimit = 63; // Not including dots
+ private const int c_defaultNameLimit = 255; // Including dots
+ private const int c_initialN = 0x80;
+ private const int c_maxint = 0x7ffffff;
+ private const int c_initialBias = 72;
+ private const int c_punycodeBase = 36;
+ private const int c_tmin = 1;
+ private const int c_tmax = 26;
+ private const int c_skew = 38;
+ private const int c_damp = 700;
+
+
+ // Legal "dot" separators (i.e: . in www.microsoft.com)
+ private static char[] c_Dots = { '.', '\u3002', '\uFF0E', '\uFF61' };
+
+ private string GetAsciiInvariant(string unicode, int index, int count)
{
- uint flags = (uint)((AllowUnassigned ? IDN_ALLOW_UNASSIGNED : 0) | (UseStd3AsciiRules ? IDN_USE_STD3_ASCII_RULES : 0));
- int length = IdnToUnicode(flags, ascii, ascii.Length, null, 0);
- int lastError;
-
- if (length == 0)
+ if (index > 0 || count < unicode.Length)
{
- lastError = Marshal.GetLastWin32Error();
- if (lastError == ERROR_INVALID_NAME)
- {
- throw new ArgumentException(Environment.GetResourceString("Argument_IdnIllegalName"), nameof(ascii));
- }
-
- throw new ArgumentException(Environment.GetResourceString("Argument_IdnBadPunycode"), nameof(ascii));
+ unicode = unicode.Substring(index, count);
}
- char [] output = new char[length];
-
- length = IdnToUnicode(flags, ascii, ascii.Length, output, length);
- if (length == 0)
+ // Check for ASCII only string, which will be unchanged
+ if (ValidateStd3AndAscii(unicode, UseStd3AsciiRules, true))
{
- lastError = Marshal.GetLastWin32Error();
- if (lastError == ERROR_INVALID_NAME)
- {
- throw new ArgumentException(Environment.GetResourceString("Argument_IdnIllegalName"), nameof(ascii));
- }
-
- throw new ArgumentException(Environment.GetResourceString("Argument_IdnBadPunycode"), nameof(ascii));
+ return unicode;
}
-
- return new String(output, 0, length);
- }
- public override bool Equals(Object obj)
- {
- IdnMapping that = obj as IdnMapping;
-
- if (that != null)
+ // Cannot be null terminated (normalization won't help us with this one, and
+ // may have returned false before checking the whole string above)
+ Debug.Assert(count >= 1, "[IdnMapping.GetAscii] Expected 0 length strings to fail before now.");
+ if (unicode[unicode.Length - 1] <= 0x1f)
{
- return this.m_bAllowUnassigned == that.m_bAllowUnassigned &&
- this.m_bUseStd3AsciiRules == that.m_bUseStd3AsciiRules;
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidCharSequence, unicode.Length - 1), nameof(unicode));
}
- return (false);
- }
+ // Have to correctly IDNA normalize the string and Unassigned flags
+ bool bHasLastDot = (unicode.Length > 0) && IsDot(unicode[unicode.Length - 1]);
- public override int GetHashCode()
- {
- return (this.m_bAllowUnassigned ? 100 : 200) + (this.m_bUseStd3AsciiRules ? 1000 : 2000);
- }
+ // Make sure we didn't normalize away something after a last dot
+ if ((!bHasLastDot) && unicode.Length > 0 && IsDot(unicode[unicode.Length - 1]))
+ {
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode));
+ }
- // Helpers
- static bool IsSupplementary(int cTest)
- {
- return cTest >= 0x10000;
- }
+ // May need to check Std3 rules again for non-ascii
+ if (UseStd3AsciiRules)
+ {
+ ValidateStd3AndAscii(unicode, true, false);
+ }
- // Is it a dot?
- // are we U+002E (., full stop), U+3002 (ideographic full stop), U+FF0E (fullwidth full stop), or
- // U+FF61 (halfwidth ideographic full stop).
- // Note: IDNA Normalization gets rid of dots now, but testing for last dot is before normalization
- static bool IsDot(char c)
- {
- return c == '.' || c == '\u3002' || c == '\uFF0E' || c == '\uFF61';
+ // Go ahead and encode it
+ return PunycodeEncode(unicode);
}
-
// See if we're only ASCII
static bool ValidateStd3AndAscii(string unicode, bool bUseStd3, bool bCheckAscii)
{
// If its empty, then its too small
if (unicode.Length == 0)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(unicode));
- Contract.EndContractBlock();
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode));
int iLastDot = -1;
@@ -379,9 +237,7 @@ namespace System.Globalization
// Aren't allowing control chars (or 7f, but idn tables catch that, they don't catch \0 at end though)
if (unicode[i] <= 0x1f)
{
- throw new ArgumentException(
- Environment.GetResourceString("Argument_InvalidCharSequence", i ),
- nameof(unicode));
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidCharSequence, i ), nameof(unicode));
}
// If its Unicode or a control character, return false (non-ascii)
@@ -393,17 +249,15 @@ namespace System.Globalization
{
// Can't have 2 dots in a row
if (i == iLastDot + 1)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(unicode));
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode));
// If its too far between dots then fail
- if (i - iLastDot > M_labelLimit + 1)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(unicode));
+ if (i - iLastDot > c_labelLimit + 1)
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode));
// If validating Std3, then char before dot can't be - char
if (bUseStd3 && i > 0)
- ValidateStd3(unicode[i-1], true);
+ ValidateStd3(unicode[i - 1], true);
// Remember where the last dot is
iLastDot = i;
@@ -418,148 +272,22 @@ namespace System.Globalization
}
// If we never had a dot, then we need to be shorter than the label limit
- if (iLastDot == -1 && unicode.Length > M_labelLimit)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(unicode));
+ if (iLastDot == -1 && unicode.Length > c_labelLimit)
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode));
// Need to validate entire string length, 1 shorter if last char wasn't a dot
- if (unicode.Length > M_defaultNameLimit - (IsDot(unicode[unicode.Length-1])? 0 : 1))
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadNameSize",
- M_defaultNameLimit - (IsDot(unicode[unicode.Length-1]) ? 0 : 1)),
- nameof(unicode));
+ if (unicode.Length > c_defaultNameLimit - (IsDot(unicode[unicode.Length - 1]) ? 0 : 1))
+ throw new ArgumentException(SR.Format(SR.Argument_IdnBadNameSize,
+ c_defaultNameLimit - (IsDot(unicode[unicode.Length - 1]) ? 0 : 1)), nameof(unicode));
// If last char wasn't a dot we need to check for trailing -
- if (bUseStd3 && !IsDot(unicode[unicode.Length-1]))
- ValidateStd3(unicode[unicode.Length-1], true);
+ if (bUseStd3 && !IsDot(unicode[unicode.Length - 1]))
+ ValidateStd3(unicode[unicode.Length - 1], true);
return true;
}
- // Validate Std3 rules for a character
- static void ValidateStd3(char c, bool bNextToDot)
- {
- // Check for illegal characters
- if ((c <= ',' || c == '/' || (c >= ':' && c <= '@') || // Lots of characters not allowed
- (c >= '[' && c <= '`') || (c >= '{' && c <= (char)0x7F)) ||
- (c == '-' && bNextToDot))
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadStd3", c), "Unicode");
- }
-
- //
- // The following punycode implementation is ported from the sample punycode.c in RFC 3492
- // Original sample code was written by Adam M. Costello.
- //
-
- // Return whether a punycode code point is flagged as being upper case.
-
- static bool HasUpperCaseFlag(char punychar)
- {
- return (punychar >= 'A' && punychar <= 'Z');
- }
-
-
- /**********************************************************/
- /* Implementation (would normally go in its own .c file): */
-
- /*** Bootstring parameters for Punycode ***/
- const int punycodeBase = 36;
- const int tmin = 1;
- const int tmax = 26;
- const int skew = 38;
- const int damp = 700;
- const int initial_bias = 72;
- const int initial_n = 0x80;
- const char delimiter = '-';
-
- /* basic(cp) tests whether cp is a basic code point: */
- static bool basic(uint cp)
- {
- // Is it in ASCII range?
- return cp < 0x80;
- }
-
- // decode_digit(cp) returns the numeric value of a basic code */
- // point (for use in representing integers) in the range 0 to */
- // punycodeBase-1, or <0 if cp is does not represent a value. */
-
- static int decode_digit(char cp)
- {
- if (cp >= '0' && cp <= '9')
- return cp - '0' + 26;
-
- // Two flavors for case differences
- if (cp >= 'a' && cp <= 'z')
- return cp - 'a';
-
- if (cp >= 'A' && cp <= 'Z')
- return cp - 'A';
-
- // Expected 0-9, A-Z or a-z, everything else is illegal
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadPunycode"), "ascii");
- }
-
- /* encode_digit(d,flag) returns the basic code point whose value */
- /* (when used for representing integers) is d, which needs to be in */
- /* the range 0 to punycodeBase-1. The lowercase form is used unless flag is */
- /* true, in which case the uppercase form is used. */
-
- static char encode_digit(int d)
- {
- Debug.Assert(d >= 0 && d < punycodeBase, "[IdnMapping.encode_digit]Expected 0 <= d < punycodeBase");
- // 26-35 map to ASCII 0-9
- if (d > 25) return (char)(d - 26 + '0');
-
- // 0-25 map to a-z or A-Z
- return (char)(d + 'a');
- }
-
-
-
- /* encode_basic(bcp,flag) forces a basic code point to lowercase */
- /* if flag is false, uppercase if flag is true, and returns */
- /* the resulting code point. The code point is unchanged if it */
- /* is caseless. The behavior is undefined if bcp is not a basic */
- /* code point. */
-
- static char encode_basic(char bcp)
- {
- if (HasUpperCaseFlag(bcp))
- bcp += (char)('a' - 'A');
-
- return bcp;
- }
-
- /*** Platform-specific constants ***/
-
- /* maxint is the maximum value of a uint variable: */
- const int maxint = 0x7ffffff;
-
- /*** Bias adaptation function ***/
-
- static int adapt(
- int delta, int numpoints, bool firsttime )
- {
- uint k;
-
- delta = firsttime ? delta / damp : delta / 2;
- Debug.Assert(numpoints != 0, "[IdnMapping.adapt]Expected non-zero numpoints.");
- delta += delta / numpoints;
-
- for (k = 0; delta > ((punycodeBase - tmin) * tmax) / 2; k += punycodeBase)
- {
- delta /= punycodeBase - tmin;
- }
-
- Debug.Assert(delta + skew != 0, "[IdnMapping.adapt]Expected non-zero delta+skew.");
- return (int)(k + (punycodeBase - tmin + 1) * delta / (delta + skew));
- }
-
- /*** Main encode function ***/
-
- /* punycode_encode() converts Unicode to Punycode. The input */
+ /* PunycodeEncode() converts Unicode to Punycode. The input */
/* is represented as an array of Unicode code points (not code */
/* units; surrogate pairs are not allowed), and the output */
/* will be represented as an array of ASCII code points. The */
@@ -584,14 +312,11 @@ namespace System.Globalization
/* value can be any of the punycode_status values defined above */
/* except punycode_bad_input; if not punycode_success, then */
/* output_size and output might contain garbage. */
-
- static String punycode_encode(String unicode)
+ static string PunycodeEncode(string unicode)
{
// 0 length strings aren't allowed
if (unicode.Length == 0)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(unicode));
- Contract.EndContractBlock();
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode));
StringBuilder output = new StringBuilder(unicode.Length);
int iNextDot = 0;
@@ -602,8 +327,8 @@ namespace System.Globalization
while (iNextDot < unicode.Length)
{
// Find end of this segment
- iNextDot = unicode.IndexOfAny(M_Dots, iAfterLastDot);
- Debug.Assert(iNextDot <= unicode.Length, "[IdnMapping.punycode_encode]IndexOfAny is broken");
+ iNextDot = unicode.IndexOfAny(c_Dots, iAfterLastDot);
+ Contract.Assert(iNextDot <= unicode.Length, "[IdnMapping.punycode_encode]IndexOfAny is broken");
if (iNextDot < 0)
iNextDot = unicode.Length;
@@ -612,14 +337,13 @@ namespace System.Globalization
{
// Only allowed to have empty sections as trailing .
if (iNextDot != unicode.Length)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(unicode));
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode));
// Last dot, stop
break;
}
// We'll need an Ace prefix
- output.Append(M_strAcePrefix);
+ output.Append(c_strAcePrefix);
// Everything resets every segment.
bool bRightToLeft = false;
@@ -642,8 +366,7 @@ namespace System.Globalization
if (eBidi != BidiCategory.RightToLeft && eBidi != BidiCategory.RightToLeftArabic)
{
// Oops, last wasn't RTL, last should be RTL if first is RTL
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadBidi"), nameof(unicode));
+ throw new ArgumentException(SR.Argument_IdnBadBidi, nameof(unicode));
}
}
@@ -653,8 +376,7 @@ namespace System.Globalization
for (basicCount = iAfterLastDot; basicCount < iNextDot; basicCount++)
{
// Can't be lonely surrogate because it would've thrown in normalization
- Debug.Assert(Char.IsLowSurrogate(unicode, basicCount) == false,
- "[IdnMapping.punycode_encode]Unexpected low surrogate");
+ Debug.Assert(Char.IsLowSurrogate(unicode, basicCount) == false, "[IdnMapping.punycode_encode]Unexpected low surrogate");
// Double check our bidi rules
BidiCategory testBidi = CharUnicodeInfo.GetBidiCategory(unicode, basicCount);
@@ -663,23 +385,20 @@ namespace System.Globalization
if (bRightToLeft && testBidi == BidiCategory.LeftToRight)
{
// Oops, throw error
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadBidi"), nameof(unicode));
+ throw new ArgumentException(SR.Argument_IdnBadBidi, nameof(unicode));
}
// If we're not RTL we can't have RTL chars
- if (!bRightToLeft && (testBidi == BidiCategory.RightToLeft ||
- testBidi == BidiCategory.RightToLeftArabic))
+ if (!bRightToLeft && (testBidi == BidiCategory.RightToLeft || testBidi == BidiCategory.RightToLeftArabic))
{
// Oops, throw error
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadBidi"), nameof(unicode));
+ throw new ArgumentException(SR.Argument_IdnBadBidi, nameof(unicode));
}
// If its basic then add it
- if (basic(unicode[basicCount]))
+ if (Basic(unicode[basicCount]))
{
- output.Append(encode_basic(unicode[basicCount]));
+ output.Append(EncodeBasic(unicode[basicCount]));
numProcessed++;
}
// If its a surrogate, skip the next since our bidi category tester doesn't handle it.
@@ -693,16 +412,15 @@ namespace System.Globalization
if (numBasicCodePoints == iNextDot - iAfterLastDot)
{
// Get rid of xn-- and this segments done
- output.Remove(iOutputAfterLastDot, M_strAcePrefix.Length);
+ output.Remove(iOutputAfterLastDot, c_strAcePrefix.Length);
}
else
{
// If it has some non-basic code points the input cannot start with xn--
- if (unicode.Length - iAfterLastDot >= M_strAcePrefix.Length &&
- unicode.Substring(iAfterLastDot, M_strAcePrefix.Length).Equals(
- M_strAcePrefix, StringComparison.OrdinalIgnoreCase))
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadPunycode"), nameof(unicode));
+ if (unicode.Length - iAfterLastDot >= c_strAcePrefix.Length &&
+ unicode.Substring(iAfterLastDot, c_strAcePrefix.Length).Equals(
+ c_strAcePrefix, StringComparison.OrdinalIgnoreCase))
+ throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(unicode));
// Need to do ACE encoding
int numSurrogatePairs = 0; // number of surrogate pairs so far
@@ -710,13 +428,13 @@ namespace System.Globalization
// Add a delimiter (-) if we had any basic code points (between basic and encoded pieces)
if (numBasicCodePoints > 0)
{
- output.Append(delimiter);
+ output.Append(c_delimiter);
}
// Initialize the state
- int n = initial_n;
+ int n = c_initialN;
int delta = 0;
- int bias = initial_bias;
+ int bias = c_initialBias;
// Main loop
while (numProcessed < (iNextDot - iAfterLastDot))
@@ -726,7 +444,7 @@ namespace System.Globalization
int j;
int m;
int test = 0;
- for (m = maxint, j = iAfterLastDot;
+ for (m = c_maxint, j = iAfterLastDot;
j < iNextDot;
j += IsSupplementary(test) ? 2 : 1)
{
@@ -751,27 +469,24 @@ namespace System.Globalization
if (test < n)
{
delta++;
- Debug.Assert(delta > 0, "[IdnMapping.cs]2 punycode_encode - delta overflowed int");
+ Contract.Assert(delta > 0, "[IdnMapping.cs]2 punycode_encode - delta overflowed int");
}
if (test == n)
{
// Represent delta as a generalized variable-length integer:
int q, k;
- for (q = delta, k = punycodeBase; ; k += punycodeBase)
+ for (q = delta, k = c_punycodeBase; ; k += c_punycodeBase)
{
- int t = k <= bias ? tmin :
- k >= bias + tmax ? tmax : k - bias;
+ int t = k <= bias ? c_tmin : k >= bias + c_tmax ? c_tmax : k - bias;
if (q < t) break;
- Debug.Assert(punycodeBase != t, "[IdnMapping.punycode_encode]Expected punycodeBase (36) to be != t");
-
- int mod;
- q = Math.DivRem(q - t, punycodeBase - t, out mod);
- output.Append(encode_digit(t + mod));
+ Debug.Assert(c_punycodeBase != t, "[IdnMapping.punycode_encode]Expected c_punycodeBase (36) to be != t");
+ output.Append(EncodeDigit(t + (q - t) % (c_punycodeBase - t)));
+ q = (q - t) / (c_punycodeBase - t);
}
- output.Append(encode_digit(q));
- bias = adapt(delta, (numProcessed - numSurrogatePairs) + 1, numProcessed == numBasicCodePoints);
+ output.Append(EncodeDigit(q));
+ bias = Adapt(delta, (numProcessed - numSurrogatePairs) + 1, numProcessed == numBasicCodePoints);
delta = 0;
numProcessed++;
@@ -789,9 +504,8 @@ namespace System.Globalization
}
// Make sure its not too big
- if (output.Length - iOutputAfterLastDot > M_labelLimit)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(unicode));
+ if (output.Length - iOutputAfterLastDot > c_labelLimit)
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode));
// Done with this segment, add dot if necessary
if (iNextDot != unicode.Length)
@@ -802,19 +516,61 @@ namespace System.Globalization
}
// Throw if we're too long
- if (output.Length > M_defaultNameLimit - (IsDot(unicode[unicode.Length-1]) ? 0 : 1))
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadNameSize",
- M_defaultNameLimit - (IsDot(unicode[unicode.Length-1]) ? 0 : 1)),
- nameof(unicode));
-
+ if (output.Length > c_defaultNameLimit - (IsDot(unicode[unicode.Length-1]) ? 0 : 1))
+ throw new ArgumentException(SR.Format(SR.Argument_IdnBadNameSize,
+ c_defaultNameLimit - (IsDot(unicode[unicode.Length-1]) ? 0 : 1)), nameof(unicode));
// Return our output string
return output.ToString();
}
- /*** Main decode function ***/
+ // Is it a dot?
+ // are we U+002E (., full stop), U+3002 (ideographic full stop), U+FF0E (fullwidth full stop), or
+ // U+FF61 (halfwidth ideographic full stop).
+ // Note: IDNA Normalization gets rid of dots now, but testing for last dot is before normalization
+ private static bool IsDot(char c)
+ {
+ return c == '.' || c == '\u3002' || c == '\uFF0E' || c == '\uFF61';
+ }
+
+ private static bool IsSupplementary(int cTest)
+ {
+ return cTest >= 0x10000;
+ }
- /* punycode_decode() converts Punycode to Unicode. The input is */
+ private static bool Basic(uint cp)
+ {
+ // Is it in ASCII range?
+ return cp < 0x80;
+ }
+
+ // Validate Std3 rules for a character
+ private static void ValidateStd3(char c, bool bNextToDot)
+ {
+ // Check for illegal characters
+ if ((c <= ',' || c == '/' || (c >= ':' && c <= '@') || // Lots of characters not allowed
+ (c >= '[' && c <= '`') || (c >= '{' && c <= (char)0x7F)) ||
+ (c == '-' && bNextToDot))
+ throw new ArgumentException(SR.Format(SR.Argument_IdnBadStd3, c), nameof(c));
+ }
+
+ private string GetUnicodeInvariant(string ascii, int index, int count)
+ {
+ if (index > 0 || count < ascii.Length)
+ {
+ // We're only using part of the string
+ ascii = ascii.Substring(index, count);
+ }
+ // Convert Punycode to Unicode
+ string strUnicode = PunycodeDecode(ascii);
+
+ // Output name MUST obey IDNA rules & round trip (casing differences are allowed)
+ if (!ascii.Equals(GetAscii(strUnicode), StringComparison.OrdinalIgnoreCase))
+ throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(ascii));
+
+ return strUnicode;
+ }
+
+ /* PunycodeDecode() converts Punycode to Unicode. The input is */
/* represented as an array of ASCII code points, and the output */
/* will be represented as an array of Unicode code points. The */
/* input_length is the number of code points in the input. The */
@@ -835,19 +591,16 @@ namespace System.Globalization
/* decoder will never need to write an output_length greater than */
/* input_length, because of how the encoding is defined. */
- static String punycode_decode( String ascii )
+ private static string PunycodeDecode(string ascii)
{
// 0 length strings aren't allowed
if (ascii.Length == 0)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(ascii));
- Contract.EndContractBlock();
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(ascii));
// Throw if we're too long
- if (ascii.Length > M_defaultNameLimit - (IsDot(ascii[ascii.Length-1]) ? 0 : 1))
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadNameSize",
- M_defaultNameLimit - (IsDot(ascii[ascii.Length-1]) ? 0 : 1)), nameof(ascii));
+ if (ascii.Length > c_defaultNameLimit - (IsDot(ascii[ascii.Length-1]) ? 0 : 1))
+ throw new ArgumentException(SR.Format(SR.Argument_IdnBadNameSize,
+ c_defaultNameLimit - (IsDot(ascii[ascii.Length-1]) ? 0 : 1)), nameof(ascii));
// output stringbuilder
StringBuilder output = new StringBuilder(ascii.Length);
@@ -869,51 +622,35 @@ namespace System.Globalization
{
// Only allowed to have empty sections as trailing .
if (iNextDot != ascii.Length)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(ascii));
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(ascii));
// Last dot, stop
break;
}
// In either case it can't be bigger than segment size
- if (iNextDot - iAfterLastDot > M_labelLimit)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(ascii));
+ if (iNextDot - iAfterLastDot > c_labelLimit)
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(ascii));
// See if this section's ASCII or ACE
- if (ascii.Length < M_strAcePrefix.Length + iAfterLastDot ||
- !ascii.Substring(iAfterLastDot, M_strAcePrefix.Length).Equals(
- M_strAcePrefix, StringComparison.OrdinalIgnoreCase))
+ if (ascii.Length < c_strAcePrefix.Length + iAfterLastDot ||
+ !ascii.Substring(iAfterLastDot,c_strAcePrefix.Length).Equals(c_strAcePrefix, StringComparison.OrdinalIgnoreCase))
{
- // Its supposed to be just ASCII
- // Actually, for non xn-- stuff do we want to allow Unicode?
- // for (int i = iAfterLastDot; i < iNextDot; i++)
- // {
- // // Only ASCII is allowed
- // if (ascii[i] >= 0x80)
- // throw new ArgumentException(Environment.GetResourceString(
- // "Argument_IdnBadPunycode"), nameof(ascii));
-// }
-
// Its ASCII, copy it
output.Append(ascii.Substring(iAfterLastDot, iNextDot - iAfterLastDot));
-
- // ASCII doesn't have BIDI issues
}
else
{
// Not ASCII, bump up iAfterLastDot to be after ACE Prefix
- iAfterLastDot += M_strAcePrefix.Length;
+ iAfterLastDot += c_strAcePrefix.Length;
// Get number of basic code points (where delimiter is)
// numBasicCodePoints < 0 if there're no basic code points
- int iTemp = ascii.LastIndexOf(delimiter, iNextDot - 1);
+ int iTemp = ascii.LastIndexOf(c_delimiter, iNextDot - 1);
// Trailing - not allowed
if (iTemp == iNextDot - 1)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadPunycode"), nameof(ascii));
+ throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii));
int numBasicCodePoints;
if (iTemp <= iAfterLastDot)
@@ -924,31 +661,25 @@ namespace System.Globalization
// Copy all the basic code points, making sure they're all in the allowed range,
// and losing the casing for all of them.
- for (int copyAscii = iAfterLastDot;
- copyAscii < iAfterLastDot + numBasicCodePoints;
- copyAscii++)
+ for (int copyAscii = iAfterLastDot; copyAscii < iAfterLastDot + numBasicCodePoints; copyAscii++)
{
// Make sure we don't allow unicode in the ascii part
if (ascii[copyAscii] > 0x7f)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadPunycode"), nameof(ascii));
+ throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii));
// When appending make sure they get lower cased
- output.Append((char)(ascii[copyAscii] >= 'A' && ascii[copyAscii] <='Z' ?
- ascii[copyAscii] - 'A' + 'a' :
- ascii[copyAscii]));
+ output.Append((char)(ascii[copyAscii] >= 'A' && ascii[copyAscii] <='Z' ? ascii[copyAscii] - 'A' + 'a' : ascii[copyAscii]));
}
}
// Get ready for main loop. Start at beginning if we didn't have any
// basic code points, otherwise start after the -.
// asciiIndex will be next character to read from ascii
- int asciiIndex = iAfterLastDot +
- ( numBasicCodePoints > 0 ? numBasicCodePoints + 1 : 0);
+ int asciiIndex = iAfterLastDot + (numBasicCodePoints > 0 ? numBasicCodePoints + 1 : 0);
// initialize our state
- int n = initial_n;
- int bias = initial_bias;
+ int n = c_initialN;
+ int bias = c_initialBias;
int i = 0;
int w, k;
@@ -965,58 +696,43 @@ namespace System.Globalization
/* value at the end to obtain delta. */
int oldi = i;
- for (w = 1, k = punycodeBase; ; k += punycodeBase)
+ for (w = 1, k = c_punycodeBase; ; k += c_punycodeBase)
{
// Check to make sure we aren't overrunning our ascii string
if (asciiIndex >= iNextDot)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadPunycode"), nameof(ascii));
+ throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii));
// decode the digit from the next char
- int digit = decode_digit(ascii[asciiIndex++]);
+ int digit = DecodeDigit(ascii[asciiIndex++]);
Debug.Assert(w > 0, "[IdnMapping.punycode_decode]Expected w > 0");
- if (digit > (maxint - i) / w)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadPunycode"), nameof(ascii));
+ if (digit > (c_maxint - i) / w)
+ throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii));
i += (int)(digit * w);
- int t = k <= bias ? tmin :
- k >= bias + tmax ? tmax : k - bias;
- if (digit < t) break;
- Debug.Assert(punycodeBase != t, "[IdnMapping.punycode_decode]Expected t != punycodeBase (36)");
- if (w > maxint / (punycodeBase - t))
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadPunycode"), nameof(ascii));
- w *= (punycodeBase - t);
+ int t = k <= bias ? c_tmin : k >= bias + c_tmax ? c_tmax : k - bias;
+ if (digit < t)
+ break;
+ Debug.Assert(c_punycodeBase != t, "[IdnMapping.punycode_decode]Expected t != c_punycodeBase (36)");
+ if (w > c_maxint / (c_punycodeBase - t))
+ throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii));
+ w *= (c_punycodeBase - t);
}
- bias = adapt(i - oldi,
- (output.Length - iOutputAfterLastDot - numSurrogatePairs) + 1, oldi == 0);
+ bias = Adapt(i - oldi, (output.Length - iOutputAfterLastDot - numSurrogatePairs) + 1, oldi == 0);
/* i was supposed to wrap around from output.Length to 0, */
/* incrementing n each time, so we'll fix that now: */
Debug.Assert((output.Length - iOutputAfterLastDot - numSurrogatePairs) + 1 > 0,
"[IdnMapping.punycode_decode]Expected to have added > 0 characters this segment");
- if (i / ((output.Length - iOutputAfterLastDot - numSurrogatePairs) + 1) > maxint - n)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadPunycode"), nameof(ascii));
+ if (i / ((output.Length - iOutputAfterLastDot - numSurrogatePairs) + 1) > c_maxint - n)
+ throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii));
n += (int)(i / (output.Length - iOutputAfterLastDot - numSurrogatePairs + 1));
i %= (output.Length - iOutputAfterLastDot - numSurrogatePairs + 1);
- // If it was flagged it needs to be capitalized
- // if (HasUpperCaseFlag(ascii[asciiIndex - 1]))
- // {
- // /* Case of last character determines uppercase flag: */
- // // Any casing stuff need to happen last.
- // If we wanted to reverse the IDNA casing data
- // n = MakeNUpperCase(n)
- // }
-
// Make sure n is legal
if ((n < 0 || n > 0x10ffff) || (n >= 0xD800 && n <= 0xDFFF))
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadPunycode"), nameof(ascii));
+ throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii));
// insert n at position i of the output: Really tricky if we have surrogates
int iUseInsertLocation;
@@ -1027,14 +743,11 @@ namespace System.Globalization
{
// Hard way, we have supplimentary characters
int iCount;
- for (iCount = i, iUseInsertLocation = iOutputAfterLastDot;
- iCount > 0;
- iCount--, iUseInsertLocation++)
+ for (iCount = i, iUseInsertLocation = iOutputAfterLastDot; iCount > 0; iCount--, iUseInsertLocation++)
{
// If its a surrogate, we have to go one more
if (iUseInsertLocation >= output.Length)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadPunycode"), nameof(ascii));
+ throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii));
if (Char.IsSurrogate(output[iUseInsertLocation]))
iUseInsertLocation++;
}
@@ -1071,34 +784,27 @@ namespace System.Globalization
for (int iTest = iOutputAfterLastDot; iTest < output.Length; iTest++)
{
// This might happen if we run into a pair
- if (Char.IsLowSurrogate(output.ToString(), iTest)) continue;
+ if (Char.IsLowSurrogate(output.ToString(), iTest))
+ continue;
// Check to see if its LTR
eBidi = CharUnicodeInfo.GetBidiCategory(output.ToString(), iTest);
if ((bRightToLeft && eBidi == BidiCategory.LeftToRight) ||
- (!bRightToLeft && (eBidi == BidiCategory.RightToLeft ||
- eBidi == BidiCategory.RightToLeftArabic)))
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadBidi"), nameof(ascii));
-
- // Make it lower case if we must (so we can test IsNormalized later)
- // if (output[iTest] >= 'A' && output[iTest] <= 'Z')
- // output[iTest] = (char)(output[iTest] + (char)('a' - 'A'));
+ (!bRightToLeft && (eBidi == BidiCategory.RightToLeft || eBidi == BidiCategory.RightToLeftArabic)))
+ throw new ArgumentException(SR.Argument_IdnBadBidi, nameof(ascii));
}
// Its also a requirement that the last one be RTL if 1st is RTL
if (bRightToLeft && eBidi != BidiCategory.RightToLeft && eBidi != BidiCategory.RightToLeftArabic)
{
// Oops, last wasn't RTL, last should be RTL if first is RTL
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadBidi"), nameof(ascii));
+ throw new ArgumentException(SR.Argument_IdnBadBidi, nameof(ascii));
}
}
// See if this label was too long
- if (iNextDot - iAfterLastDot > M_labelLimit)
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadLabelSize"), nameof(ascii));
+ if (iNextDot - iAfterLastDot > c_labelLimit)
+ throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(ascii));
// Done with this segment, add dot if necessary
if (iNextDot != ascii.Length)
@@ -1109,79 +815,84 @@ namespace System.Globalization
}
// Throw if we're too long
- if (output.Length > M_defaultNameLimit - (IsDot(output[output.Length-1]) ? 0 : 1))
- throw new ArgumentException(Environment.GetResourceString(
- "Argument_IdnBadNameSize",
- M_defaultNameLimit -(IsDot(output[output.Length-1]) ? 0 : 1)), nameof(ascii));
+ if (output.Length > c_defaultNameLimit - (IsDot(output[output.Length-1]) ? 0 : 1))
+ throw new ArgumentException(SR.Format(SR.Argument_IdnBadNameSize, c_defaultNameLimit - (IsDot(output[output.Length-1]) ? 0 : 1)), nameof(ascii));
// Return our output string
return output.ToString();
}
- /*
- The previous punycode implimentation is based on the sample code in RFC 3492
-
- Full Copyright Statement
-
- Copyright (C) The Internet Society (2003). All Rights Reserved.
-
- This document and translations of it may be copied and furnished to
- others, and derivative works that comment on or otherwise explain it
- or assist in its implementation may be prepared, copied, published
- and distributed, in whole or in part, without restriction of any
- kind, provided that the above copyright notice and this paragraph are
- included on all such copies and derivative works. However, this
- document itself may not be modified in any way, such as by removing
- the copyright notice or references to the Internet Society or other
- Internet organizations, except as needed for the purpose of
- developing Internet standards in which case the procedures for
- copyrights defined in the Internet Standards process must be
- followed, or as required to translate it into languages other than
- English.
-
- The limited permissions granted above are perpetual and will not be
- revoked by the Internet Society or its successors or assigns.
-
- This document and the information contained herein is provided on an
- "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
- TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
- BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
- HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
- MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-
- private const int IDN_ALLOW_UNASSIGNED = 0x1;
- private const int IDN_USE_STD3_ASCII_RULES = 0x2;
+ // DecodeDigit(cp) returns the numeric value of a basic code */
+ // point (for use in representing integers) in the range 0 to */
+ // c_punycodeBase-1, or <0 if cp is does not represent a value. */
+
+ private static int DecodeDigit(char cp)
+ {
+ if (cp >= '0' && cp <= '9')
+ return cp - '0' + 26;
+
+ // Two flavors for case differences
+ if (cp >= 'a' && cp <= 'z')
+ return cp - 'a';
+
+ if (cp >= 'A' && cp <= 'Z')
+ return cp - 'A';
+
+ // Expected 0-9, A-Z or a-z, everything else is illegal
+ throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(cp));
+ }
+
+ private static int Adapt(int delta, int numpoints, bool firsttime)
+ {
+ uint k;
+
+ delta = firsttime ? delta / c_damp : delta / 2;
+ Debug.Assert(numpoints != 0, "[IdnMapping.adapt]Expected non-zero numpoints.");
+ delta += delta / numpoints;
+
+ for (k = 0; delta > ((c_punycodeBase - c_tmin) * c_tmax) / 2; k += c_punycodeBase)
+ {
+ delta /= c_punycodeBase - c_tmin;
+ }
+
+ Debug.Assert(delta + c_skew != 0, "[IdnMapping.adapt]Expected non-zero delta+skew.");
+ return (int)(k + (c_punycodeBase - c_tmin + 1) * delta / (delta + c_skew));
+ }
+
+ /* EncodeBasic(bcp,flag) forces a basic code point to lowercase */
+ /* if flag is false, uppercase if flag is true, and returns */
+ /* the resulting code point. The code point is unchanged if it */
+ /* is caseless. The behavior is undefined if bcp is not a basic */
+ /* code point. */
+
+ static char EncodeBasic(char bcp)
+ {
+ if (HasUpperCaseFlag(bcp))
+ bcp += (char)('a' - 'A');
+
+ return bcp;
+ }
+
+ // Return whether a punycode code point is flagged as being upper case.
+ private static bool HasUpperCaseFlag(char punychar)
+ {
+ return (punychar >= 'A' && punychar <= 'Z');
+ }
+
+ /* EncodeDigit(d,flag) returns the basic code point whose value */
+ /* (when used for representing integers) is d, which needs to be in */
+ /* the range 0 to punycodeBase-1. The lowercase form is used unless flag is */
+ /* true, in which case the uppercase form is used. */
+
+ private static char EncodeDigit(int d)
+ {
+ Debug.Assert(d >= 0 && d < c_punycodeBase, "[IdnMapping.encode_digit]Expected 0 <= d < punycodeBase");
+ // 26-35 map to ASCII 0-9
+ if (d > 25) return (char)(d - 26 + '0');
+
+ // 0-25 map to a-z or A-Z
+ return (char)(d + 'a');
+ }
- private const int ERROR_INVALID_NAME = 123;
-
-
- [SuppressUnmanagedCodeSecurityAttribute()]
- [DllImport("normaliz.dll", CharSet=CharSet.Unicode, SetLastError=true)]
- private static extern int IdnToAscii(
- uint dwFlags,
- [InAttribute()]
- [MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
- String lpUnicodeCharStr,
- int cchUnicodeChar,
- [System.Runtime.InteropServices.OutAttribute()]
-
- char [] lpASCIICharStr,
- int cchASCIIChar);
-
- [SuppressUnmanagedCodeSecurityAttribute()]
- [DllImport("normaliz.dll", CharSet=CharSet.Unicode, SetLastError=true)]
- private static extern int IdnToUnicode(
- uint dwFlags,
- [InAttribute()]
- [MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
- string lpASCIICharStr,
- int cchASCIIChar,
- [System.Runtime.InteropServices.OutAttribute()]
-
- char [] lpUnicodeCharStr,
- int cchUnicodeChar);
}
}
-