< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 175
Coverable lines: 175
Total lines: 263
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 50
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)0%440%
GetBytes(...)0%440%
GetMemoryBlock(...)0%220%
GetVirtualHandleMemoryBlock(...)0%220%
GetBlobReader(...)100%110%
GetNextHandle(...)0%660%
GetVirtualBlobBytes(...)0%440%
GetDocumentName(...)0%880%
DocumentNameEquals(...)0%20200%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Internal/BlobHeap.cs

#LineLine coverage
 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
 4using System.Reflection.Internal;
 5using System.Threading;
 6
 7namespace System.Reflection.Metadata.Ecma335
 8{
 9    internal struct BlobHeap
 10    {
 11        private static byte[][]? s_virtualValues;
 12
 13        internal readonly MemoryBlock Block;
 14        private VirtualHeap? _lazyVirtualHeap;
 15
 16        internal BlobHeap(MemoryBlock block, MetadataKind metadataKind)
 017        {
 018            _lazyVirtualHeap = null;
 019            Block = block;
 20
 021            if (s_virtualValues == null && metadataKind != MetadataKind.Ecma335)
 022            {
 023                var blobs = new byte[(int)BlobHandle.VirtualIndex.Count][];
 24
 025                blobs[(int)BlobHandle.VirtualIndex.ContractPublicKeyToken] = new byte[]
 026                {
 027                    0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A
 028                };
 29
 030                blobs[(int)BlobHandle.VirtualIndex.ContractPublicKey] = new byte[]
 031                {
 032                    0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00,
 033                    0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
 034                    0x07, 0xD1, 0xFA, 0x57, 0xC4, 0xAE, 0xD9, 0xF0, 0xA3, 0x2E, 0x84, 0xAA, 0x0F, 0xAE, 0xFD, 0x0D,
 035                    0xE9, 0xE8, 0xFD, 0x6A, 0xEC, 0x8F, 0x87, 0xFB, 0x03, 0x76, 0x6C, 0x83, 0x4C, 0x99, 0x92, 0x1E,
 036                    0xB2, 0x3B, 0xE7, 0x9A, 0xD9, 0xD5, 0xDC, 0xC1, 0xDD, 0x9A, 0xD2, 0x36, 0x13, 0x21, 0x02, 0x90,
 037                    0x0B, 0x72, 0x3C, 0xF9, 0x80, 0x95, 0x7F, 0xC4, 0xE1, 0x77, 0x10, 0x8F, 0xC6, 0x07, 0x77, 0x4F,
 038                    0x29, 0xE8, 0x32, 0x0E, 0x92, 0xEA, 0x05, 0xEC, 0xE4, 0xE8, 0x21, 0xC0, 0xA5, 0xEF, 0xE8, 0xF1,
 039                    0x64, 0x5C, 0x4C, 0x0C, 0x93, 0xC1, 0xAB, 0x99, 0x28, 0x5D, 0x62, 0x2C, 0xAA, 0x65, 0x2C, 0x1D,
 040                    0xFA, 0xD6, 0x3D, 0x74, 0x5D, 0x6F, 0x2D, 0xE5, 0xF1, 0x7E, 0x5E, 0xAF, 0x0F, 0xC4, 0x96, 0x3D,
 041                    0x26, 0x1C, 0x8A, 0x12, 0x43, 0x65, 0x18, 0x20, 0x6D, 0xC0, 0x93, 0x34, 0x4D, 0x5A, 0xD2, 0x93
 042                };
 43
 044                blobs[(int)BlobHandle.VirtualIndex.AttributeUsage_AllowSingle] = new byte[]
 045                {
 046                    // preamble:
 047                    0x01, 0x00,
 048                    // target (template parameter):
 049                    0x00, 0x00, 0x00, 0x00,
 050                    // named arg count:
 051                    0x01, 0x00,
 052                    // SERIALIZATION_TYPE_PROPERTY
 053                    0x54,
 054                    // ELEMENT_TYPE_BOOLEAN
 055                    0x02,
 056                    // "AllowMultiple".Length
 057                    0x0D,
 058                    // "AllowMultiple"
 059                    0x41, 0x6C, 0x6C, 0x6F, 0x77, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x6C, 0x65,
 060                    // false
 061                    0x00
 062                };
 63
 064                blobs[(int)BlobHandle.VirtualIndex.AttributeUsage_AllowMultiple] = new byte[]
 065                {
 066                    // preamble:
 067                    0x01, 0x00,
 068                    // target (template parameter):
 069                    0x00, 0x00, 0x00, 0x00,
 070                    // named arg count:
 071                    0x01, 0x00,
 072                    // SERIALIZATION_TYPE_PROPERTY
 073                    0x54,
 074                    // ELEMENT_TYPE_BOOLEAN
 075                    0x02,
 076                    // "AllowMultiple".Length
 077                    0x0D,
 078                    // "AllowMultiple"
 079                    0x41, 0x6C, 0x6C, 0x6F, 0x77, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x6C, 0x65,
 080                    // true
 081                    0x01
 082                };
 83
 084                s_virtualValues = blobs;
 085            }
 086        }
 87
 88        internal byte[] GetBytes(BlobHandle handle, bool unique = true)
 089        {
 090            if (handle.IsVirtual)
 091            {
 092                return GetVirtualBlobBytes(handle, unique);
 93            }
 94
 095            int offset = handle.GetHeapOffset();
 96            int bytesRead;
 097            int numberOfBytes = Block.PeekCompressedInteger(offset, out bytesRead);
 098            if (numberOfBytes == BlobReader.InvalidCompressedInteger)
 099            {
 0100                return Array.Empty<byte>();
 101            }
 102
 0103            return Block.PeekBytes(offset + bytesRead, numberOfBytes);
 0104        }
 105
 106        internal MemoryBlock GetMemoryBlock(BlobHandle handle)
 0107        {
 0108            if (handle.IsVirtual)
 0109            {
 0110                return GetVirtualHandleMemoryBlock(handle);
 111            }
 112
 113            int offset, size;
 0114            Block.PeekHeapValueOffsetAndSize(handle.GetHeapOffset(), out offset, out size);
 0115            return Block.GetMemoryBlockAt(offset, size);
 0116        }
 117
 118        private MemoryBlock GetVirtualHandleMemoryBlock(BlobHandle handle)
 0119        {
 0120            var heap = VirtualHeap.GetOrCreateVirtualHeap(ref _lazyVirtualHeap);
 121
 0122            lock (heap)
 0123            {
 0124                if (!heap.TryGetMemoryBlock(handle.RawValue, out var block))
 0125                {
 0126                    block = heap.AddBlob(handle.RawValue, GetVirtualBlobBytes(handle, unique: false));
 0127                }
 128
 0129                return block;
 130            }
 0131        }
 132
 133        internal BlobReader GetBlobReader(BlobHandle handle)
 0134        {
 0135            return new BlobReader(GetMemoryBlock(handle));
 0136        }
 137
 138        internal BlobHandle GetNextHandle(BlobHandle handle)
 0139        {
 0140            if (handle.IsVirtual)
 0141            {
 0142                return default(BlobHandle);
 143            }
 144
 145            int offset, size;
 0146            if (!Block.PeekHeapValueOffsetAndSize(handle.GetHeapOffset(), out offset, out size))
 0147            {
 0148                return default(BlobHandle);
 149            }
 150
 0151            int nextIndex = offset + size;
 0152            if (nextIndex >= Block.Length)
 0153            {
 0154                return default(BlobHandle);
 155            }
 156
 0157            return BlobHandle.FromOffset(nextIndex);
 0158        }
 159
 160        internal static byte[] GetVirtualBlobBytes(BlobHandle handle, bool unique)
 0161        {
 0162            BlobHandle.VirtualIndex index = handle.GetVirtualIndex();
 0163            byte[] result = s_virtualValues![(int)index];
 164
 0165            switch (index)
 166            {
 167                case BlobHandle.VirtualIndex.AttributeUsage_AllowMultiple:
 168                case BlobHandle.VirtualIndex.AttributeUsage_AllowSingle:
 0169                    result = (byte[])result.Clone();
 0170                    handle.SubstituteTemplateParameters(result);
 0171                    break;
 172
 173                default:
 0174                    if (unique)
 0175                    {
 0176                        result = (byte[])result.Clone();
 0177                    }
 0178                    break;
 179            }
 180
 0181            return result;
 0182        }
 183
 184        public string GetDocumentName(DocumentNameBlobHandle handle)
 0185        {
 0186            var blobReader = GetBlobReader(handle);
 187
 188            // Spec: separator is an ASCII encoded character in range [0x01, 0x7F], or byte 0 to represent an empty sepa
 0189            int separator = blobReader.ReadByte();
 0190            if (separator > 0x7f)
 0191            {
 0192                throw new BadImageFormatException(SR.InvalidDocumentName);
 193            }
 194
 0195            var pooledBuilder = PooledStringBuilder.GetInstance();
 0196            var builder = pooledBuilder.Builder;
 0197            bool isFirstPart = true;
 0198            while (blobReader.RemainingBytes > 0)
 0199            {
 0200                if (separator != 0 && !isFirstPart)
 0201                {
 0202                    builder.Append((char)separator);
 0203                }
 204
 0205                var partReader = GetBlobReader(blobReader.ReadBlobHandle());
 206
 0207                builder.Append(partReader.ReadUTF8(partReader.Length));
 0208                isFirstPart = false;
 0209            }
 210
 0211            return pooledBuilder.ToStringAndFree();
 0212        }
 213
 214        internal bool DocumentNameEquals(DocumentNameBlobHandle handle, string other, bool ignoreCase)
 0215        {
 0216            var blobReader = GetBlobReader(handle);
 217
 218            // Spec: separator is an ASCII encoded character in range [0x01, 0x7F], or byte 0 to represent an empty sepa
 0219            int separator = blobReader.ReadByte();
 0220            if (separator > 0x7f)
 0221            {
 0222                return false;
 223            }
 224
 0225            int ignoreCaseMask = StringUtils.IgnoreCaseMask(ignoreCase);
 0226            int otherIndex = 0;
 0227            bool isFirstPart = true;
 0228            while (blobReader.RemainingBytes > 0)
 0229            {
 0230                if (separator != 0 && !isFirstPart)
 0231                {
 0232                    if (otherIndex == other.Length || !StringUtils.IsEqualAscii(other[otherIndex], separator, ignoreCase
 0233                    {
 0234                        return false;
 235                    }
 236
 0237                    otherIndex++;
 0238                }
 239
 0240                var partBlock = GetMemoryBlock(blobReader.ReadBlobHandle());
 241
 242                int firstDifferenceIndex;
 0243                var result = partBlock.Utf8NullTerminatedFastCompare(0, other, otherIndex, out firstDifferenceIndex, ter
 0244                if (result == MemoryBlock.FastComparisonResult.Inconclusive)
 0245                {
 0246                    return GetDocumentName(handle).Equals(other, ignoreCase ? StringComparison.OrdinalIgnoreCase : Strin
 247                }
 248
 0249                if (result == MemoryBlock.FastComparisonResult.Unequal ||
 0250                    firstDifferenceIndex - otherIndex != partBlock.Length)
 0251                {
 0252                    return false;
 253                }
 254
 0255                otherIndex = firstDifferenceIndex;
 0256                isFirstPart = false;
 0257            }
 258
 0259            return otherIndex == other.Length;
 0260        }
 261    }
 262}
 263