Skip to content

Commit

Permalink
Merge pull request dotnet#533 from stephentoub/merge_v1
Browse files Browse the repository at this point in the history
Merge v1 to master
  • Loading branch information
stephentoub committed Jan 28, 2015
2 parents b7a78c8 + a932651 commit e296ec9
Show file tree
Hide file tree
Showing 42 changed files with 21,177 additions and 5 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ Today, the repository contains the following components:
* **System.Diagnostics.Process**. Provides access to local and remote processes, and enables the starting and
stopping of local system processes.

* **System.Globalization.Extensions**. Provides classes for performing unicode string normalization, culture-specific string comparisons and support the use of non-ASCII characters for Internet domain names.

* **System.IO.FileSystem**. Provides access to the file system, including support for enumerating and manipulating
file system objects and for reading and writing files via streams.

Expand Down
2 changes: 1 addition & 1 deletion dir.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<SourceDir>$(ProjectDir)src\</SourceDir>
<BinDir>$(ProjectDir)bin\</BinDir>
<TestWorkingDir>$(BinDir)tests\</TestWorkingDir>
<PackagesDir>$(SourceDir)packages\</PackagesDir>
<PackagesDir>$(ProjectDir)packages\</PackagesDir>
<ToolsDir>$(PackagesDir)Microsoft.DotNet.BuildTools.$(BuildToolsVersion)\lib\</ToolsDir>
</PropertyGroup>

Expand Down
65 changes: 65 additions & 0 deletions src/Common/src/Interop/Interop.Globalization.Extensions.manual.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
// These are error codes we get back from the Normalization DLL
internal const int ERROR_SUCCESS = 0;
internal const int ERROR_NOT_ENOUGH_MEMORY = 8;
internal const int ERROR_INVALID_PARAMETER = 87;
internal const int ERROR_INSUFFICIENT_BUFFER = 122;
internal const int ERROR_NO_UNICODE_TRANSLATION = 1113;

// The VM can override the last error code with this value in debug builds
// so this value for us is equivalent to ERROR_SUCCESS
internal const int LAST_ERROR_TRASH_VALUE = 42424;

internal partial class mincore
{
//
// Idn APIs
//

[DllImport("api-ms-win-core-localization-l1-2-0.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int IdnToAscii(
uint dwFlags,
string lpUnicodeCharStr,
int cchUnicodeChar,
[System.Runtime.InteropServices.OutAttribute()]

char[] lpASCIICharStr,
int cchASCIIChar);

[DllImport("api-ms-win-core-localization-l1-2-0.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int IdnToUnicode(
uint dwFlags,
string lpASCIICharStr,
int cchASCIIChar,
[System.Runtime.InteropServices.OutAttribute()]

char[] lpUnicodeCharStr,
int cchUnicodeChar);
//
// Normalization APIs
//

[DllImport("api-ms-win-core-normalization-l1-1-0.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool IsNormalizedString(int normForm, string source, int length);

[DllImport("api-ms-win-core-normalization-l1-1-0.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int NormalizeString(
int normForm,
string source,
int sourceLength,
[System.Runtime.InteropServices.OutAttribute()]
char[] destenation,
int destenationLength);
}
}




245 changes: 245 additions & 0 deletions src/Common/src/System/Globalization/IdnMapping.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

//
// This file contains the IDN functions and implementation.
//
// This allows encoding of non-ASCII domain names in a "punycode" form,
// for example:
//
// \u5B89\u5BA4\u5948\u7F8E\u6075-with-SUPER-MONKEYS
//
// is encoded as:
//
// xn---with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n
//
// Additional options are provided to allow unassigned IDN characters and
// to validate according to the Std3ASCII Rules (like DNS names).
//
// There are also rules regarding bidirectionality of text and the length
// of segments.
//
// For additional rules see also:
// 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)
//

using System.Runtime.InteropServices;
using System.Diagnostics.Contracts;

namespace System.Globalization
{
// IdnMapping class used to map names to Punycode
#if INTERNAL_GLOBALIZATION_EXTENSIONS
internal
#else
public
#endif
sealed class IdnMapping
{
bool m_bAllowUnassigned;
bool m_bUseStd3AsciiRules;

public IdnMapping()
{
}

public bool AllowUnassigned
{
get
{
return this.m_bAllowUnassigned;
}

set
{
this.m_bAllowUnassigned = value;
}
}

public bool UseStd3AsciiRules
{
get
{
return this.m_bUseStd3AsciiRules;
}

set
{
this.m_bUseStd3AsciiRules = value;
}
}

// Gets ASCII (Punycode) version of the string
public String GetAscii(String unicode)
{
return GetAscii(unicode, 0);
}

public String GetAscii(String unicode, int index)
{
if (unicode == null) throw new ArgumentNullException("unicode");
Contract.EndContractBlock();
return GetAscii(unicode, index, unicode.Length - index);
}

public String GetAscii(String unicode, int index, int count)
{
if (unicode == null) throw new ArgumentNullException("unicode");
if (index < 0 || count < 0)
throw new ArgumentOutOfRangeException((index < 0) ? "index" : "count", SR.ArgumentOutOfRange_NeedNonNegNum);
if (index > unicode.Length)
throw new ArgumentOutOfRangeException("byteIndex", SR.ArgumentOutOfRange_Index);
if (index > unicode.Length - count)
throw new ArgumentOutOfRangeException("unicode", SR.ArgumentOutOfRange_IndexCountBuffer);
Contract.EndContractBlock();

// We're only using part of the string
unicode = unicode.Substring(index, count);

return GetAsciiUsingOS(unicode);
}

[System.Security.SecuritySafeCritical]
private String GetAsciiUsingOS(String unicode)
{
if (unicode.Length == 0)
{
throw new ArgumentException(SR.Argument_IdnBadLabelSize, "unicode");
}

if (unicode[unicode.Length - 1] == 0)
{
throw new ArgumentException(SR.Format(SR.Argument_InvalidCharSequence, unicode.Length - 1), "unicode");
}

uint flags = (uint)((AllowUnassigned ? IDN_ALLOW_UNASSIGNED : 0) | (UseStd3AsciiRules ? IDN_USE_STD3_ASCII_RULES : 0));
int length = Interop.mincore.IdnToAscii(flags, unicode, unicode.Length, null, 0);

int lastError;

if (length == 0)
{
lastError = Marshal.GetLastWin32Error();
if (lastError == ERROR_INVALID_NAME)
{
throw new ArgumentException(SR.Argument_IdnIllegalName, "unicode");
}

throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, "unicode");
}

char[] output = new char[length];

length = Interop.mincore.IdnToAscii(flags, unicode, unicode.Length, output, length);
if (length == 0)
{
lastError = Marshal.GetLastWin32Error();
if (lastError == ERROR_INVALID_NAME)
{
throw new ArgumentException(SR.Argument_IdnIllegalName, "unicode");
}

throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, "unicode");
}

return new String(output, 0, length);
}

// Gets Unicode version of the string. Normalized and limited to IDNA characters.
public String GetUnicode(String ascii)
{
return GetUnicode(ascii, 0);
}

public String GetUnicode(String ascii, int index)
{
if (ascii == null) throw new ArgumentNullException("ascii");
Contract.EndContractBlock();
return GetUnicode(ascii, index, ascii.Length - index);
}

public String GetUnicode(String ascii, int index, int count)
{
if (ascii == null) throw new ArgumentNullException("ascii");
if (index < 0 || count < 0)
throw new ArgumentOutOfRangeException((index < 0) ? "index" : "count", SR.ArgumentOutOfRange_NeedNonNegNum);
if (index > ascii.Length)
throw new ArgumentOutOfRangeException("byteIndex", SR.ArgumentOutOfRange_Index);
if (index > ascii.Length - count)
throw new ArgumentOutOfRangeException("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("ascii", SR.Argument_IdnBadPunycode);
Contract.EndContractBlock();

// We're only using part of the string
ascii = ascii.Substring(index, count);

return GetUnicodeUsingOS(ascii);
}


[System.Security.SecuritySafeCritical]
private string GetUnicodeUsingOS(string ascii)
{
uint flags = (uint)((AllowUnassigned ? IDN_ALLOW_UNASSIGNED : 0) | (UseStd3AsciiRules ? IDN_USE_STD3_ASCII_RULES : 0));
int length = Interop.mincore.IdnToUnicode(flags, ascii, ascii.Length, null, 0);
int lastError;

if (length == 0)
{
lastError = Marshal.GetLastWin32Error();
if (lastError == ERROR_INVALID_NAME)
{
throw new ArgumentException(SR.Argument_IdnIllegalName, "ascii");
}

throw new ArgumentException(SR.Argument_IdnBadPunycode, "ascii");
}

char[] output = new char[length];

length = Interop.mincore.IdnToUnicode(flags, ascii, ascii.Length, output, length);
if (length == 0)
{
lastError = Marshal.GetLastWin32Error();
if (lastError == ERROR_INVALID_NAME)
{
throw new ArgumentException(SR.Argument_IdnIllegalName, "ascii");
}

throw new ArgumentException(SR.Argument_IdnBadPunycode, "ascii");
}

return new String(output, 0, length);
}

public override bool Equals(Object obj)
{
IdnMapping that = obj as IdnMapping;

if (that != null)
{
return this.m_bAllowUnassigned == that.m_bAllowUnassigned &&
this.m_bUseStd3AsciiRules == that.m_bUseStd3AsciiRules;
}

return (false);
}

public override int GetHashCode()
{
return (this.m_bAllowUnassigned ? 100 : 200) + (this.m_bUseStd3AsciiRules ? 1000 : 2000);
}

private const int IDN_ALLOW_UNASSIGNED = 0x1;
private const int IDN_USE_STD3_ASCII_RULES = 0x2;
private const int ERROR_INVALID_NAME = 123;
}
}

Loading

0 comments on commit e296ec9

Please sign in to comment.