| | | 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 | | |
| | | 4 | | using System.Diagnostics; |
| | | 5 | | using System.Reflection.Internal; |
| | | 6 | | using System.Text; |
| | | 7 | | |
| | | 8 | | namespace System.Reflection.Metadata |
| | | 9 | | { |
| | | 10 | | /// <summary> |
| | | 11 | | /// Provides the <see cref="MetadataReader"/> with a custom mechanism for decoding |
| | | 12 | | /// byte sequences in metadata that represent text. |
| | | 13 | | /// </summary> |
| | | 14 | | /// <remarks> |
| | | 15 | | /// This can be used for the following purposes: |
| | | 16 | | /// |
| | | 17 | | /// 1) To customize the treatment of invalid input. When no decoder is provided, |
| | | 18 | | /// the <see cref="MetadataReader"/> uses the default fallback replacement |
| | | 19 | | /// with \uFFFD) |
| | | 20 | | /// |
| | | 21 | | /// 2) To reuse existing strings instead of allocating a new one for each decoding |
| | | 22 | | /// operation. |
| | | 23 | | /// </remarks> |
| | | 24 | | public class MetadataStringDecoder |
| | | 25 | | { |
| | | 26 | | /// <summary> |
| | | 27 | | /// Gets the encoding used by this instance. |
| | | 28 | | /// </summary> |
| | 0 | 29 | | public Encoding Encoding { get; } |
| | | 30 | | |
| | | 31 | | /// <summary> |
| | | 32 | | /// The default decoder used by <see cref="MetadataReader"/> to decode UTF-8 when |
| | | 33 | | /// no decoder is provided to the constructor. |
| | | 34 | | /// </summary> |
| | 0 | 35 | | public static MetadataStringDecoder DefaultUTF8 { get; } = new MetadataStringDecoder(Encoding.UTF8); |
| | | 36 | | |
| | | 37 | | /// <summary> |
| | | 38 | | /// Creates a <see cref="MetadataStringDecoder"/> for the given encoding. |
| | | 39 | | /// </summary> |
| | | 40 | | /// <param name="encoding">The encoding to use.</param> |
| | | 41 | | /// <remarks> |
| | | 42 | | /// To cache and reuse existing strings. Create a derived class and override <see cref="GetString(byte*, int)"/> |
| | | 43 | | /// </remarks> |
| | 0 | 44 | | public MetadataStringDecoder(Encoding encoding) |
| | 0 | 45 | | { |
| | 0 | 46 | | if (encoding is null) |
| | 0 | 47 | | { |
| | 0 | 48 | | Throw.ArgumentNull(nameof(encoding)); |
| | | 49 | | } |
| | | 50 | | |
| | | 51 | | // Non-enforcement of (encoding is UTF8Encoding) here is by design. |
| | | 52 | | // |
| | | 53 | | // This type is not itself aware of any particular encoding. However, the constructor argument that accepts |
| | | 54 | | // MetadataStringDecoder argument is validated however because it must be a UTF8 decoder. |
| | | 55 | | |
| | 0 | 56 | | Encoding = encoding; |
| | 0 | 57 | | } |
| | | 58 | | |
| | | 59 | | /// <summary> |
| | | 60 | | /// The mechanism through which the <see cref="MetadataReader"/> obtains strings |
| | | 61 | | /// for byte sequences in metadata. Override this to cache strings if required. |
| | | 62 | | /// Otherwise, it is implemented by forwarding straight to <see cref="Encoding"/> |
| | | 63 | | /// and every call will allocate a new string. |
| | | 64 | | /// </summary> |
| | | 65 | | /// <param name="bytes">Pointer to bytes to decode.</param> |
| | | 66 | | /// <param name="byteCount">Number of bytes to decode.</param> |
| | | 67 | | /// <returns>The decoded string.</returns> |
| | | 68 | | public virtual unsafe string GetString(byte* bytes, int byteCount) |
| | 0 | 69 | | { |
| | 0 | 70 | | Debug.Assert(Encoding != null); |
| | | 71 | | |
| | 0 | 72 | | return Encoding.GetString(bytes, byteCount); |
| | 0 | 73 | | } |
| | | 74 | | } |
| | | 75 | | } |
| | | 76 | | |