Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
/// <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>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,71 @@ 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;
Name = name;
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; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -37,6 +39,8 @@ public EncodingProvider() { }
return enc;
}

public virtual IEnumerable<EncodingInfo> GetEncodings() => Array.Empty<EncodingInfo>();

internal static void AddProvider(EncodingProvider provider)
{
if (provider == null)
Expand Down Expand Up @@ -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);
Expand All @@ -78,6 +82,29 @@ internal static void AddProvider(EncodingProvider provider)
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<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)
Expand Down
3 changes: 2 additions & 1 deletion src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; } }
Expand All @@ -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<System.Text.EncodingInfo> GetEncodings() { throw null; }
}
public enum NormalizationForm
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -185,6 +185,7 @@ private unsafe void LoadCodePageTables()
LoadManagedCodePage();
}


// Look up the code page pointer
private unsafe bool FindCodePage(int codePage)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
}
Loading