1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-08 03:27:04 +09:00

Support the Encoding enumeration in the Encoding Providers (#37528)

* Support the Encoding enumeration in the Encoding Providers

* Fix build

* Fix netstandard build

* Address the feedback

* More Feedback

* More Feedback
This commit is contained in:
Tarek Mahmoud Sayed 2020-06-08 19:21:01 -07:00 committed by GitHub
parent ed075a7ec4
commit efe9663636
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 319 additions and 30 deletions

View file

@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
@ -290,8 +291,15 @@ namespace System.Text
GetEncoding(EncodingTable.GetCodePageFromName(name), encoderFallback, decoderFallback);
}
// Return a list of all EncodingInfo objects describing all of our encodings
public static EncodingInfo[] GetEncodings() => EncodingTable.GetEncodings();
/// <summary>
/// Get the <see cref="EncodingInfo"/> list from the runtime and all registered encoding providers
/// </summary>
/// <returns>The list of the <see cref="EncodingProvider"/> objects</returns>
public static EncodingInfo[] GetEncodings()
{
Dictionary<int, EncodingInfo>? result = EncodingProvider.GetEncodingListFromProviders();
return result == null ? EncodingTable.GetEncodings() : EncodingTable.GetEncodings(result);
}
public virtual byte[] GetPreamble() => Array.Empty<byte>();

View file

@ -6,6 +6,24 @@ namespace System.Text
{
public sealed class EncodingInfo
{
/// <summary>
/// Construct an <see cref="EncodingInfo"/> object.
/// </summary>
/// <param name="provider">The <see cref="EncodingProvider"/> object which created this <see cref="EncodingInfo"/> object</param>
/// <param name="codePage">The encoding codepage</param>
/// <param name="name">The encoding name</param>
/// <param name="displayName">The encoding display name</param>
/// <returns></returns>
public EncodingInfo(EncodingProvider provider, int codePage, string name, string displayName) : this(codePage, name, displayName)
{
if (name == null || displayName == null || provider == null)
{
throw new ArgumentNullException(name == null ? nameof(name) : (displayName == null ? nameof(displayName) : nameof(provider)));
}
Provider = provider;
}
internal EncodingInfo(int codePage, string name, string displayName)
{
CodePage = codePage;
@ -13,27 +31,46 @@ namespace System.Text
DisplayName = displayName;
}
/// <summary>
/// Get the encoding codepage number
/// </summary>
/// <value>The codepage integer number</value>
public int CodePage { get; }
/// <summary>
/// Get the encoding name
/// </summary>
/// <value>The encoding name string</value>
public string Name { get; }
/// <summary>
/// Get the encoding display name
/// </summary>
/// <value>The encoding display name string</value>
public string DisplayName { get; }
public Encoding GetEncoding()
{
return Encoding.GetEncoding(CodePage);
}
/// <summary>
/// Get the <see cref="Encoding"/> object match the information in the <see cref="EncodingInfo"/> object
/// </summary>
/// <returns>The <see cref="Encoding"/> object</returns>
public Encoding GetEncoding() => Provider?.GetEncoding(CodePage) ?? Encoding.GetEncoding(CodePage);
public override bool Equals(object? value)
{
if (value is EncodingInfo that)
{
return this.CodePage == that.CodePage;
}
return false;
}
/// <summary>
/// Compare this <see cref="EncodingInfo"/> object to other object.
/// </summary>
/// <param name="value">The other object to compare with this object</param>
/// <returns>True if the value object is EncodingInfo object and has a codepage equals to this EncodingInfo object codepage. Otherwise, it returns False</returns>
public override bool Equals(object? value) => value is EncodingInfo that && CodePage == that.CodePage;
/// <summary>
/// Get a hashcode representing the current EncodingInfo object.
/// </summary>
/// <returns>The integer value representing the hash code of the EncodingInfo object.</returns>
public override int GetHashCode()
{
return CodePage;
}
internal EncodingProvider? Provider { get; }
}
}

View file

@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
namespace System.Text
{
public abstract class EncodingProvider
@ -37,6 +39,8 @@ namespace System.Text
return enc;
}
public virtual IEnumerable<EncodingInfo> GetEncodings() => Array.Empty<EncodingInfo>();
internal static void AddProvider(EncodingProvider provider)
{
if (provider == null)
@ -64,10 +68,10 @@ namespace System.Text
internal static Encoding? GetEncodingFromProvider(int codepage)
{
if (s_providers == null)
EncodingProvider[]? providers = s_providers;
if (providers == null)
return null;
EncodingProvider[] providers = s_providers;
foreach (EncodingProvider provider in providers)
{
Encoding? enc = provider.GetEncoding(codepage);
@ -78,6 +82,29 @@ namespace System.Text
return null;
}
internal static Dictionary<int, EncodingInfo>? GetEncodingListFromProviders()
{
EncodingProvider[]? providers = s_providers;
if (providers == null)
return null;
Dictionary<int, EncodingInfo> result = new Dictionary<int, EncodingInfo>();
foreach (EncodingProvider provider in providers)
{
IEnumerable<EncodingInfo>? encodingInfoList = provider.GetEncodings();
if (encodingInfoList != null)
{
foreach (EncodingInfo ei in encodingInfoList)
{
result.TryAdd(ei.CodePage, ei);
}
}
}
return result;
}
internal static Encoding? GetEncodingFromProvider(string encodingName)
{
if (s_providers == null)

View file

@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
@ -105,20 +106,49 @@ namespace System.Text
// Return a list of all EncodingInfo objects describing all of our encodings
internal static EncodingInfo[] GetEncodings()
{
EncodingInfo[] arrayEncodingInfo = new EncodingInfo[s_mappedCodePages.Length];
ushort[] mappedCodePages = s_mappedCodePages;
EncodingInfo[] arrayEncodingInfo = new EncodingInfo[mappedCodePages.Length];
string webNames = s_webNames;
int[] webNameIndices = s_webNameIndices;
for (int i = 0; i < s_mappedCodePages.Length; i++)
for (int i = 0; i < mappedCodePages.Length; i++)
{
arrayEncodingInfo[i] = new EncodingInfo(
s_mappedCodePages[i],
s_webNames[s_webNameIndices[i]..s_webNameIndices[i + 1]],
GetDisplayName(s_mappedCodePages[i], i)
mappedCodePages[i],
webNames[webNameIndices[i]..webNameIndices[i + 1]],
GetDisplayName(mappedCodePages[i], i)
);
}
return arrayEncodingInfo;
}
internal static EncodingInfo[] GetEncodings(Dictionary<int, EncodingInfo> encodingInfoList)
{
Debug.Assert(encodingInfoList != null);
ushort[] mappedCodePages = s_mappedCodePages;
string webNames = s_webNames;
int[] webNameIndices = s_webNameIndices;
for (int i = 0; i < mappedCodePages.Length; i++)
{
if (!encodingInfoList.ContainsKey(mappedCodePages[i]))
{
encodingInfoList[mappedCodePages[i]] = new EncodingInfo(mappedCodePages[i], webNames[webNameIndices[i]..webNameIndices[i + 1]],
GetDisplayName(mappedCodePages[i], i));
}
}
var result = new EncodingInfo[encodingInfoList.Count];
int j = 0;
foreach (KeyValuePair<int, EncodingInfo> pair in encodingInfoList)
{
result[j++] = pair.Value;
}
return result;
}
internal static CodePageDataItem? GetCodePageDataItem(int codePage)
{
if (s_codePageToCodePageData == null)

View file

@ -10265,7 +10265,7 @@ namespace System.Text
}
public sealed partial class EncodingInfo
{
internal EncodingInfo() { }
public EncodingInfo(System.Text.EncodingProvider provider, int codePage, string name, string displayName) {}
public int CodePage { get { throw null; } }
public string DisplayName { get { throw null; } }
public string Name { get { throw null; } }
@ -10280,6 +10280,7 @@ namespace System.Text
public virtual System.Text.Encoding? GetEncoding(int codepage, System.Text.EncoderFallback encoderFallback, System.Text.DecoderFallback decoderFallback) { throw null; }
public abstract System.Text.Encoding? GetEncoding(string name);
public virtual System.Text.Encoding? GetEncoding(string name, System.Text.EncoderFallback encoderFallback, System.Text.DecoderFallback decoderFallback) { throw null; }
public virtual System.Collections.Generic.IEnumerable<System.Text.EncodingInfo> GetEncodings() { throw null; }
}
public enum NormalizationForm
{

View file

@ -1,9 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Nullable>enable</Nullable>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<TargetFrameworks>$(NetCoreAppCurrent);netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Compile Include="System.Text.Encoding.CodePages.cs" />
<Compile Include="System.Text.Encoding.CodePages.netcoreapp.cs" Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)'" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)'">
<ProjectReference Include="../../System.Runtime/ref/System.Runtime.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace System.Text
{
public sealed partial class CodePagesEncodingProvider : System.Text.EncodingProvider
{
public override System.Collections.Generic.IEnumerable<System.Text.EncodingInfo> GetEncodings() { throw null; }
}
}

View file

@ -2,13 +2,13 @@
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
<TargetFrameworks>$(NetCoreAppCurrent)-Windows_NT;netstandard2.0;netcoreapp2.0-Windows_NT;netstandard2.0-Windows_NT</TargetFrameworks>
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppCurrent)-Windows_NT;netstandard2.0;netcoreapp2.0-Windows_NT;netstandard2.0-Windows_NT</TargetFrameworks>
<ExcludeCurrentNetCoreAppFromPackage>true</ExcludeCurrentNetCoreAppFromPackage>
</PropertyGroup>
<!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
<PropertyGroup>
<!-- copy the Windows-specific implementation to net461 folder so that restore without a RID works -->
<PackageTargetFramework Condition="$(TargetFramework.StartsWith('netstandard')) and '$(TargetsWindows)' == 'true'">netstandard2.0;net461</PackageTargetFramework>
<PackageTargetFramework Condition="$(TargetFramework.StartsWith('netstandard')) and '$(TargetsWindows)' == 'true'">netstandard2.0;net461</PackageTargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="Microsoft\Win32\SafeHandles\SafeAllocHHandle.cs" />
@ -48,6 +48,13 @@
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard')) and '$(TargetsWindows)' != 'true' ">
<Compile Include="System\Text\CodePagesEncodingProvider.Default.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)' and '$(TargetsWindows)' != 'true' ">
<Compile Include="System\Text\CodePagesEncodingProvider.Default.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)'">
<Compile Include="System\Text\CodePagesEncodingProvider.netcoreapp.cs" />
<Compile Include="System\Text\BaseCodePageEncoding.netcoreapp.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Data\codepages.nlp">
<LogicalName>codepages.nlp</LogicalName>

View file

@ -41,7 +41,7 @@ namespace System.Text
// WORD byteReplace; // 2 bytes = 48 // default replacement byte(s)
// BYTE[] data; // data section
// }
internal abstract class BaseCodePageEncoding : EncodingNLS, ISerializable
internal abstract partial class BaseCodePageEncoding : EncodingNLS, ISerializable
{
internal const string CODE_PAGE_DATA_FILE_NAME = "codepages.nlp";
@ -185,6 +185,7 @@ namespace System.Text
LoadManagedCodePage();
}
// Look up the code page pointer
private unsafe bool FindCodePage(int codePage)
{

View file

@ -0,0 +1,60 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.CompilerServices;
namespace System.Text
{
internal abstract partial class BaseCodePageEncoding : EncodingNLS, ISerializable
{
internal static unsafe EncodingInfo [] GetEncodings(CodePagesEncodingProvider provider)
{
lock (s_streamLock)
{
s_codePagesEncodingDataStream.Seek(CODEPAGE_DATA_FILE_HEADER_SIZE, SeekOrigin.Begin);
int codePagesCount;
fixed (byte* pBytes = &s_codePagesDataHeader[0])
{
CodePageDataFileHeader* pDataHeader = (CodePageDataFileHeader*)pBytes;
codePagesCount = pDataHeader->CodePageCount;
}
EncodingInfo [] encodingInfoList = new EncodingInfo[codePagesCount];
CodePageIndex codePageIndex = default;
Span<byte> pCodePageIndex = new Span<byte>(&codePageIndex, Unsafe.SizeOf<CodePageIndex>());
for (int i = 0; i < codePagesCount; i++)
{
s_codePagesEncodingDataStream.Read(pCodePageIndex);
string codePageName;
switch (codePageIndex.CodePage)
{
// Fixup some encoding names.
case 950: codePageName = "big5"; break;
case 10002: codePageName = "x-mac-chinesetrad"; break;
case 20833: codePageName = "x-ebcdic-koreanextended"; break;
default: codePageName = new string(&codePageIndex.CodePageName); break;
}
string? resourceName = EncodingNLS.GetLocalizedEncodingNameResource(codePageIndex.CodePage);
string? displayName = null;
if (resourceName != null && resourceName.StartsWith("Globalization_cp_", StringComparison.OrdinalIgnoreCase))
{
displayName = SR.GetResourceString(resourceName);
}
encodingInfoList[i] = new EncodingInfo(provider, codePageIndex.CodePage, codePageName, displayName ?? codePageName);
}
return encodingInfoList;
}
}
}
}

View file

@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
namespace System.Text
{
public sealed partial class CodePagesEncodingProvider : EncodingProvider
{
public override System.Collections.Generic.IEnumerable<System.Text.EncodingInfo> GetEncodings() => BaseCodePageEncoding.GetEncodings(this);
}
}

View file

@ -392,7 +392,7 @@ namespace System.Text
}
}
private static string? GetLocalizedEncodingNameResource(int codePage) =>
internal static string? GetLocalizedEncodingNameResource(int codePage) =>
codePage switch
{
37 => SR.Globalization_cp_37,
@ -549,12 +549,34 @@ namespace System.Text
_webName = EncodingTable.GetWebNameFromCodePage(CodePage);
if (_webName == null)
{
throw new NotSupportedException(
SR.Format(SR.NotSupported_NoCodepageData, CodePage));
throw new NotSupportedException(SR.Format(SR.NotSupported_NoCodepageData, CodePage));
}
}
return _webName;
}
}
public override string HeaderName =>
CodePage switch
{
932 => "iso-2022-jp",
50221 => "iso-2022-jp",
50225 => "euc-kr",
_ => WebName,
};
public override string BodyName =>
CodePage switch
{
932 => "iso-2022-jp",
1250 => "iso-8859-2",
1251 => "koi8-r",
1252 => "iso-8859-1",
1253 => "iso-8859-7",
1254 => "iso-8859-9",
50221 => "iso-2022-jp",
50225 => "iso-2022-kr",
_ => WebName,
};
}
}

View file

@ -188,7 +188,7 @@ namespace System.Text
}
}
//Nope, we didn't find it.
// Nope, we didn't find it.
return null;
}
}

View file

@ -0,0 +1,67 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.DotNet.RemoteExecutor;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Xunit;
namespace System.Text.Tests
{
public partial class EncodingTest : IClassFixture<CultureSetup>
{
private class EncodingInformation
{
public EncodingInformation(int codePage, string name)
{
CodePage = codePage;
Name = name;
}
public int CodePage { get; }
public string Name { get; }
}
private static EncodingInformation [] s_defaultEncoding = new EncodingInformation []
{
new EncodingInformation(1200, "utf-16"),
new EncodingInformation(1201, "utf-16BE"),
new EncodingInformation(12000, "utf-32"),
new EncodingInformation(12001, "utf-32BE"),
new EncodingInformation(20127, "us-ascii"),
new EncodingInformation(28591, "iso-8859-1"),
new EncodingInformation(65001, "utf-8")
};
[Fact]
public void TestGetEncodings()
{
RemoteExecutor.Invoke(() => {
EncodingInfo [] list = Encoding.GetEncodings();
foreach (EncodingInformation eInfo in s_defaultEncoding)
{
Assert.NotNull(list.FirstOrDefault(o => o.CodePage == eInfo.CodePage && o.Name == eInfo.Name));
}
}).Dispose();
}
[Fact]
public void TestGetEncodingsWithProvider()
{
RemoteExecutor.Invoke(() => {
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
foreach (EncodingInfo ei in Encoding.GetEncodings())
{
Encoding encoding = ei.GetEncoding();
Assert.Equal(ei.CodePage, encoding.CodePage);
Assert.True(ei.Name.Equals(encoding.WebName, StringComparison.OrdinalIgnoreCase), $"Encodinginfo.Name `{ei.Name}` != Encoding.WebName `{encoding.WebName}`");
}
}).Dispose();
}
}
}

View file

@ -6,5 +6,6 @@
<ItemGroup>
<Compile Include="EncoderFallbackBufferHelper.cs" />
<Compile Include="EncodingCodePages.cs" />
<Compile Include="EncodingCodePages.netcoreapp.cs" Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)'" />
</ItemGroup>
</Project>