IdnMapping.Windows.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Diagnostics;
  5. using System.Diagnostics.CodeAnalysis;
  6. using System.Runtime.InteropServices;
  7. namespace System.Globalization
  8. {
  9. public sealed partial class IdnMapping
  10. {
  11. private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count)
  12. {
  13. Debug.Assert(!GlobalizationMode.Invariant);
  14. Debug.Assert(unicodeString != null && unicodeString.Length >= count);
  15. uint flags = Flags;
  16. // Determine the required length
  17. int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, null, 0);
  18. if (length == 0)
  19. {
  20. ThrowForZeroLength(unicode: true);
  21. }
  22. // Do the conversion
  23. const int StackAllocThreshold = 512; // arbitrary limit to switch from stack to heap allocation
  24. if (length < StackAllocThreshold)
  25. {
  26. char* output = stackalloc char[length];
  27. return GetAsciiCore(unicodeString, unicode, count, flags, output, length);
  28. }
  29. else
  30. {
  31. char[] output = new char[length];
  32. fixed (char* pOutput = &output[0])
  33. {
  34. return GetAsciiCore(unicodeString, unicode, count, flags, pOutput, length);
  35. }
  36. }
  37. }
  38. private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count, uint flags, char* output, int outputLength)
  39. {
  40. Debug.Assert(!GlobalizationMode.Invariant);
  41. Debug.Assert(unicodeString != null && unicodeString.Length >= count);
  42. int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, output, outputLength);
  43. if (length == 0)
  44. {
  45. ThrowForZeroLength(unicode: true);
  46. }
  47. Debug.Assert(length == outputLength);
  48. return GetStringForOutput(unicodeString, unicode, count, output, length);
  49. }
  50. private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count)
  51. {
  52. Debug.Assert(!GlobalizationMode.Invariant);
  53. Debug.Assert(asciiString != null && asciiString.Length >= count);
  54. uint flags = Flags;
  55. // Determine the required length
  56. int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, null, 0);
  57. if (length == 0)
  58. {
  59. ThrowForZeroLength(unicode: false);
  60. }
  61. // Do the conversion
  62. const int StackAllocThreshold = 512; // arbitrary limit to switch from stack to heap allocation
  63. if (length < StackAllocThreshold)
  64. {
  65. char* output = stackalloc char[length];
  66. return GetUnicodeCore(asciiString, ascii, count, flags, output, length);
  67. }
  68. else
  69. {
  70. char[] output = new char[length];
  71. fixed (char* pOutput = &output[0])
  72. {
  73. return GetUnicodeCore(asciiString, ascii, count, flags, pOutput, length);
  74. }
  75. }
  76. }
  77. private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength)
  78. {
  79. Debug.Assert(!GlobalizationMode.Invariant);
  80. Debug.Assert(asciiString != null && asciiString.Length >= count);
  81. int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, output, outputLength);
  82. if (length == 0)
  83. {
  84. ThrowForZeroLength(unicode: false);
  85. }
  86. Debug.Assert(length == outputLength);
  87. return GetStringForOutput(asciiString, ascii, count, output, length);
  88. }
  89. // -----------------------------
  90. // ---- PAL layer ends here ----
  91. // -----------------------------
  92. private uint Flags
  93. {
  94. get
  95. {
  96. int flags =
  97. (AllowUnassigned ? Interop.Normaliz.IDN_ALLOW_UNASSIGNED : 0) |
  98. (UseStd3AsciiRules ? Interop.Normaliz.IDN_USE_STD3_ASCII_RULES : 0);
  99. return (uint)flags;
  100. }
  101. }
  102. [DoesNotReturn]
  103. private static void ThrowForZeroLength(bool unicode)
  104. {
  105. int lastError = Marshal.GetLastWin32Error();
  106. throw new ArgumentException(
  107. lastError == Interop.Errors.ERROR_INVALID_NAME ? SR.Argument_IdnIllegalName :
  108. (unicode ? SR.Argument_InvalidCharSequenceNoIndex : SR.Argument_IdnBadPunycode),
  109. unicode ? "unicode" : "ascii");
  110. }
  111. }
  112. }