diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs
index 3f0d0350610bad..08257200289838 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs
@@ -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 @@ public static Encoding GetEncoding(string name,
GetEncoding(EncodingTable.GetCodePageFromName(name), encoderFallback, decoderFallback);
}
- // Return a list of all EncodingInfo objects describing all of our encodings
- public static EncodingInfo[] GetEncodings() => EncodingTable.GetEncodings();
+ ///
+ /// Get the list from the runtime and all registered encoding providers
+ ///
+ /// The list of the objects
+ public static EncodingInfo[] GetEncodings()
+ {
+ Dictionary? result = EncodingProvider.GetEncodingListFromProviders();
+ return result == null ? EncodingTable.GetEncodings() : EncodingTable.GetEncodings(result);
+ }
public virtual byte[] GetPreamble() => Array.Empty();
diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingInfo.cs
index febecfa6651f6b..b1ce0cd5c62672 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingInfo.cs
@@ -6,6 +6,24 @@ namespace System.Text
{
public sealed class EncodingInfo
{
+ ///
+ /// Construct an object.
+ ///
+ /// The object which created this object
+ /// The encoding codepage
+ /// The encoding name
+ /// The encoding display name
+ ///
+ 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 @@ internal EncodingInfo(int codePage, string name, string displayName)
DisplayName = displayName;
}
+ ///
+ /// Get the encoding codepage number
+ ///
+ /// The codepage integer number
public int CodePage { get; }
+
+ ///
+ /// Get the encoding name
+ ///
+ /// The encoding name string
public string Name { get; }
+
+ ///
+ /// Get the encoding display name
+ ///
+ /// The encoding display name string
public string DisplayName { get; }
- public Encoding GetEncoding()
- {
- return Encoding.GetEncoding(CodePage);
- }
+ ///
+ /// Get the object match the information in the object
+ ///
+ /// The object
+ 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;
- }
+ ///
+ /// Compare this object to other object.
+ ///
+ /// The other object to compare with this object
+ /// True if the value object is EncodingInfo object and has a codepage equals to this EncodingInfo object codepage. Otherwise, it returns False
+ public override bool Equals(object? value) => value is EncodingInfo that && CodePage == that.CodePage;
+ ///
+ /// Get a hashcode representing the current EncodingInfo object.
+ ///
+ /// The integer value representing the hash code of the EncodingInfo object.
public override int GetHashCode()
{
return CodePage;
}
+
+ internal EncodingProvider? Provider { get; }
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingProvider.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingProvider.cs
index ac7fc541f60105..340329e25316e9 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingProvider.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingProvider.cs
@@ -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 @@ public EncodingProvider() { }
return enc;
}
+ public virtual IEnumerable GetEncodings() => Array.Empty();
+
internal static void AddProvider(EncodingProvider provider)
{
if (provider == null)
@@ -64,10 +68,10 @@ internal static void AddProvider(EncodingProvider provider)
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 @@ internal static void AddProvider(EncodingProvider provider)
return null;
}
+ internal static Dictionary? GetEncodingListFromProviders()
+ {
+ EncodingProvider[]? providers = s_providers;
+ if (providers == null)
+ return null;
+
+ Dictionary result = new Dictionary();
+
+ foreach (EncodingProvider provider in providers)
+ {
+ IEnumerable? 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)
diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs
index cc69f793d6e8f7..40904f1cbc2c38 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs
@@ -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 @@ private static int InternalGetCodePageFromName(string name)
// 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 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 pair in encodingInfoList)
+ {
+ result[j++] = pair.Value;
+ }
+
+ return result;
+ }
+
internal static CodePageDataItem? GetCodePageDataItem(int codePage)
{
if (s_codePageToCodePageData == null)
diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs
index 4c39802764aae4..7a2d7b4f6ce1b2 100644
--- a/src/libraries/System.Runtime/ref/System.Runtime.cs
+++ b/src/libraries/System.Runtime/ref/System.Runtime.cs
@@ -10262,7 +10262,7 @@ public static void RegisterProvider(System.Text.EncodingProvider provider) { }
}
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; } }
@@ -10277,6 +10277,7 @@ public EncodingProvider() { }
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 GetEncodings() { throw null; }
}
public enum NormalizationForm
{
diff --git a/src/libraries/System.Text.Encoding.CodePages/ref/System.Text.Encoding.CodePages.csproj b/src/libraries/System.Text.Encoding.CodePages/ref/System.Text.Encoding.CodePages.csproj
index 23981a702056bc..c29c17eb07596c 100644
--- a/src/libraries/System.Text.Encoding.CodePages/ref/System.Text.Encoding.CodePages.csproj
+++ b/src/libraries/System.Text.Encoding.CodePages/ref/System.Text.Encoding.CodePages.csproj
@@ -1,9 +1,13 @@
enable
- netstandard2.0
+ $(NetCoreAppCurrent);netstandard2.0
+
+
+
+
\ No newline at end of file
diff --git a/src/libraries/System.Text.Encoding.CodePages/ref/System.Text.Encoding.CodePages.netcoreapp.cs b/src/libraries/System.Text.Encoding.CodePages/ref/System.Text.Encoding.CodePages.netcoreapp.cs
new file mode 100644
index 00000000000000..06b46e94552231
--- /dev/null
+++ b/src/libraries/System.Text.Encoding.CodePages/ref/System.Text.Encoding.CodePages.netcoreapp.cs
@@ -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 GetEncodings() { throw null; }
+ }
+}
diff --git a/src/libraries/System.Text.Encoding.CodePages/src/System.Text.Encoding.CodePages.csproj b/src/libraries/System.Text.Encoding.CodePages/src/System.Text.Encoding.CodePages.csproj
index 778cc8effa9e53..88407f0f334d26 100644
--- a/src/libraries/System.Text.Encoding.CodePages/src/System.Text.Encoding.CodePages.csproj
+++ b/src/libraries/System.Text.Encoding.CodePages/src/System.Text.Encoding.CodePages.csproj
@@ -2,13 +2,13 @@
true
enable
- $(NetCoreAppCurrent)-Windows_NT;netstandard2.0;netcoreapp2.0-Windows_NT;netstandard2.0-Windows_NT
+ $(NetCoreAppCurrent);$(NetCoreAppCurrent)-Windows_NT;netstandard2.0;netcoreapp2.0-Windows_NT;netstandard2.0-Windows_NT
true
- netstandard2.0;net461
+ netstandard2.0;net461
@@ -48,6 +48,13 @@
+
+
+
+
+
+
+
codepages.nlp
diff --git a/src/libraries/System.Text.Encoding.CodePages/src/System/Text/BaseCodePageEncoding.cs b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/BaseCodePageEncoding.cs
index 7b4f57b5776287..5d26bfff272e9b 100644
--- a/src/libraries/System.Text.Encoding.CodePages/src/System/Text/BaseCodePageEncoding.cs
+++ b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/BaseCodePageEncoding.cs
@@ -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 @@ private unsafe void LoadCodePageTables()
LoadManagedCodePage();
}
+
// Look up the code page pointer
private unsafe bool FindCodePage(int codePage)
{
diff --git a/src/libraries/System.Text.Encoding.CodePages/src/System/Text/BaseCodePageEncoding.netcoreapp.cs b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/BaseCodePageEncoding.netcoreapp.cs
new file mode 100644
index 00000000000000..9c416ac0ef4fba
--- /dev/null
+++ b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/BaseCodePageEncoding.netcoreapp.cs
@@ -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 pCodePageIndex = new Span(&codePageIndex, Unsafe.SizeOf());
+
+ 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;
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.Text.Encoding.CodePages/src/System/Text/CodePagesEncodingProvider.netcoreapp.cs b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/CodePagesEncodingProvider.netcoreapp.cs
new file mode 100644
index 00000000000000..2260eee7891766
--- /dev/null
+++ b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/CodePagesEncodingProvider.netcoreapp.cs
@@ -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 GetEncodings() => BaseCodePageEncoding.GetEncodings(this);
+ }
+}
diff --git a/src/libraries/System.Text.Encoding.CodePages/src/System/Text/EncodingNLS.cs b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/EncodingNLS.cs
index 713c3201a220fa..0bcfef5d209101 100644
--- a/src/libraries/System.Text.Encoding.CodePages/src/System/Text/EncodingNLS.cs
+++ b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/EncodingNLS.cs
@@ -392,7 +392,7 @@ public override string EncodingName
}
}
- private static string? GetLocalizedEncodingNameResource(int codePage) =>
+ internal static string? GetLocalizedEncodingNameResource(int codePage) =>
codePage switch
{
37 => SR.Globalization_cp_37,
@@ -549,12 +549,34 @@ public override string WebName
_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,
+ };
}
}
diff --git a/src/libraries/System.Text.Encoding.CodePages/src/System/Text/EncodingTable.cs b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/EncodingTable.cs
index 3b2a19cc80e0cc..d663e6273e283d 100644
--- a/src/libraries/System.Text.Encoding.CodePages/src/System/Text/EncodingTable.cs
+++ b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/EncodingTable.cs
@@ -188,7 +188,7 @@ private static int CompareOrdinal(string s1, string s2, int index, int length)
}
}
- //Nope, we didn't find it.
+ // Nope, we didn't find it.
return null;
}
}
diff --git a/src/libraries/System.Text.Encoding.CodePages/tests/EncodingCodePages.netcoreapp.cs b/src/libraries/System.Text.Encoding.CodePages/tests/EncodingCodePages.netcoreapp.cs
new file mode 100644
index 00000000000000..34b899b8734c3d
--- /dev/null
+++ b/src/libraries/System.Text.Encoding.CodePages/tests/EncodingCodePages.netcoreapp.cs
@@ -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
+ {
+ 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();
+ }
+ }
+}
diff --git a/src/libraries/System.Text.Encoding.CodePages/tests/System.Text.Encoding.CodePages.Tests.csproj b/src/libraries/System.Text.Encoding.CodePages/tests/System.Text.Encoding.CodePages.Tests.csproj
index b02a5646a7f8b3..353fe29ea301c2 100644
--- a/src/libraries/System.Text.Encoding.CodePages/tests/System.Text.Encoding.CodePages.Tests.csproj
+++ b/src/libraries/System.Text.Encoding.CodePages/tests/System.Text.Encoding.CodePages.Tests.csproj
@@ -6,5 +6,6 @@
+
\ No newline at end of file