< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 135
Coverable lines: 135
Total lines: 256
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 96
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
WriteBytes(...)100%110%
WriteDouble(...)100%110%
WriteSingle(...)100%110%
WriteUInt16(...)100%110%
WriteUInt16BE(...)100%110%
WriteUInt32BE(...)100%110%
WriteUInt32(...)100%110%
WriteUInt64(...)100%110%
WriteDecimal(...)0%220%
WriteGuid(...)100%110%
WriteUTF8(...)0%20200%
GetUTF8ByteCount(...)100%110%
GetUTF8ByteCount(...)0%16160%
ValidateRange(...)0%880%
GetUserStringByteLength(...)100%110%
GetUserStringTrailingByte(...)0%50500%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/BlobUtilities.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.Buffers.Binary;
 5using System.Diagnostics;
 6using System.Reflection.Internal;
 7using System.Runtime.CompilerServices;
 8
 9namespace System.Reflection
 10{
 11    internal static class BlobUtilities
 12    {
 13        public static void WriteBytes(this byte[] buffer, int start, byte value, int byteCount)
 014        {
 015            Debug.Assert(buffer.Length > 0);
 016            new Span<byte>(buffer, start, byteCount).Fill(value);
 017        }
 18
 19        public static void WriteDouble(this byte[] buffer, int start, double value) =>
 020            WriteUInt64(buffer, start, BitConverter.DoubleToUInt64Bits(value));
 21
 22        public static void WriteSingle(this byte[] buffer, int start, float value) =>
 023            WriteUInt32(buffer, start, BitConverter.SingleToUInt32Bits(value));
 24
 25        public static void WriteUInt16(this byte[] buffer, int start, ushort value) =>
 026            BinaryPrimitives.WriteUInt16LittleEndian(buffer.AsSpan(start), value);
 27
 28        public static void WriteUInt16BE(this byte[] buffer, int start, ushort value) =>
 029            BinaryPrimitives.WriteUInt16BigEndian(buffer.AsSpan(start), value);
 30
 31        public static void WriteUInt32BE(this byte[] buffer, int start, uint value) =>
 032            BinaryPrimitives.WriteUInt32BigEndian(buffer.AsSpan(start), value);
 33
 34        public static void WriteUInt32(this byte[] buffer, int start, uint value) =>
 035            BinaryPrimitives.WriteUInt32LittleEndian(buffer.AsSpan(start), value);
 36
 37        public static void WriteUInt64(this byte[] buffer, int start, ulong value) =>
 038            BinaryPrimitives.WriteUInt64LittleEndian(buffer.AsSpan(start), value);
 39
 40        public const int SizeOfSerializedDecimal = sizeof(byte) + 3 * sizeof(uint);
 41
 42        public static void WriteDecimal(this byte[] buffer, int start, decimal value)
 043        {
 44            bool isNegative;
 45            byte scale;
 46            uint low, mid, high;
 047            value.GetBits(out isNegative, out scale, out low, out mid, out high);
 48
 049            buffer[start] = (byte)(scale | (isNegative ? 0x80 : 0x00));
 050            WriteUInt32(buffer, start + 1, low);
 051            WriteUInt32(buffer, start + 5, mid);
 052            WriteUInt32(buffer, start + 9, high);
 053        }
 54
 55        public const int SizeOfGuid = 16;
 56
 57        public static void WriteGuid(this byte[] buffer, int start, Guid value)
 058        {
 059            bool written = value.TryWriteBytes(buffer.AsSpan(start));
 60            // This function is not public, callers have to ensure that enough space is available.
 061            Debug.Assert(written);
 062        }
 63
 64        public static unsafe void WriteUTF8(this byte[] buffer, int start, char* charPtr, int charCount, int byteCount, 
 065        {
 066            Debug.Assert(byteCount >= charCount);
 67            const char ReplacementCharacter = '\uFFFD';
 68
 069            char* strEnd = charPtr + charCount;
 070            fixed (byte* bufferPtr = &buffer[0])
 071            {
 072                byte* ptr = bufferPtr + start;
 73
 074                if (byteCount == charCount)
 075                {
 076                    while (charPtr < strEnd)
 077                    {
 078                        Debug.Assert(*charPtr <= 0x7f);
 079                        *ptr++ = unchecked((byte)*charPtr++);
 080                    }
 081                }
 82                else
 083                {
 084                    while (charPtr < strEnd)
 085                    {
 086                        char c = *charPtr++;
 87
 088                        if (c < 0x80)
 089                        {
 090                            *ptr++ = (byte)c;
 091                            continue;
 92                        }
 93
 094                        if (c < 0x800)
 095                        {
 096                            ptr[0] = (byte)(((c >> 6) & 0x1F) | 0xC0);
 097                            ptr[1] = (byte)((c & 0x3F) | 0x80);
 098                            ptr += 2;
 099                            continue;
 100                        }
 101
 0102                        if (char.IsSurrogate(c))
 0103                        {
 104                            // surrogate pair
 0105                            if (char.IsHighSurrogate(c) && charPtr < strEnd && char.IsLowSurrogate(*charPtr))
 0106                            {
 0107                                int highSurrogate = c;
 0108                                int lowSurrogate = *charPtr++;
 0109                                int codepoint = (((highSurrogate - 0xd800) << 10) + lowSurrogate - 0xdc00) + 0x10000;
 0110                                ptr[0] = (byte)(((codepoint >> 18) & 0x7) | 0xF0);
 0111                                ptr[1] = (byte)(((codepoint >> 12) & 0x3F) | 0x80);
 0112                                ptr[2] = (byte)(((codepoint >> 6) & 0x3F) | 0x80);
 0113                                ptr[3] = (byte)((codepoint & 0x3F) | 0x80);
 0114                                ptr += 4;
 0115                                continue;
 116                            }
 117
 118                            // unpaired high/low surrogate
 0119                            if (!allowUnpairedSurrogates)
 0120                            {
 0121                                c = ReplacementCharacter;
 0122                            }
 0123                        }
 124
 0125                        ptr[0] = (byte)(((c >> 12) & 0xF) | 0xE0);
 0126                        ptr[1] = (byte)(((c >> 6) & 0x3F) | 0x80);
 0127                        ptr[2] = (byte)((c & 0x3F) | 0x80);
 0128                        ptr += 3;
 0129                    }
 0130                }
 131
 0132                Debug.Assert(ptr == bufferPtr + start + byteCount);
 0133                Debug.Assert(charPtr == strEnd);
 0134            }
 0135        }
 136
 137        internal static unsafe int GetUTF8ByteCount(char* str, int charCount)
 0138        {
 0139            return GetUTF8ByteCount(str, charCount, int.MaxValue, out _);
 0140        }
 141
 142        internal static unsafe int GetUTF8ByteCount(char* str, int charCount, int byteLimit, out char* remainder)
 0143        {
 0144            char* end = str + charCount;
 145
 0146            char* ptr = str;
 0147            int byteCount = 0;
 0148            while (ptr < end)
 0149            {
 150                int characterSize;
 0151                char c = *ptr++;
 0152                if (c < 0x80)
 0153                {
 0154                    characterSize = 1;
 0155                }
 0156                else if (c < 0x800)
 0157                {
 0158                    characterSize = 2;
 0159                }
 0160                else if (char.IsHighSurrogate(c) && ptr < end && char.IsLowSurrogate(*ptr))
 0161                {
 162                    // surrogate pair:
 0163                    characterSize = 4;
 0164                    ptr++;
 0165                }
 166                else
 0167                {
 0168                    characterSize = 3;
 0169                }
 170
 0171                if (byteCount + characterSize > byteLimit)
 0172                {
 0173                    ptr -= (characterSize < 4) ? 1 : 2;
 0174                    break;
 175                }
 176
 0177                byteCount += characterSize;
 0178            }
 179
 0180            remainder = ptr;
 0181            return byteCount;
 0182        }
 183
 184        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 185        internal static void ValidateRange(int bufferLength, int start, int byteCount, string byteCountParameterName)
 0186        {
 0187            if (start < 0 || start > bufferLength)
 0188            {
 0189                Throw.ArgumentOutOfRange(nameof(start));
 190            }
 191
 0192            if (byteCount < 0 || byteCount > bufferLength - start)
 0193            {
 0194                Throw.ArgumentOutOfRange(byteCountParameterName);
 195            }
 0196        }
 197
 198        internal static int GetUserStringByteLength(int characterCount)
 0199        {
 0200            return characterCount * 2 + 1;
 0201        }
 202
 203        internal static byte GetUserStringTrailingByte(string str)
 0204        {
 205            // ECMA-335 II.24.2.4:
 206            // This final byte holds the value 1 if and only if any UTF16 character within
 207            // the string has any bit set in its top byte, or its low byte is any of the following:
 208            // 0x01-0x08, 0x0E-0x1F, 0x27, 0x2D, 0x7F.  Otherwise, it holds 0.
 209            // The 1 signifies Unicode characters that require handling beyond that normally provided for 8-bit encoding
 210
 0211            foreach (char ch in str)
 0212            {
 0213                if (ch >= 0x7F)
 0214                {
 0215                    return 1;
 216                }
 217
 0218                switch ((int)ch)
 219                {
 220                    case 0x1:
 221                    case 0x2:
 222                    case 0x3:
 223                    case 0x4:
 224                    case 0x5:
 225                    case 0x6:
 226                    case 0x7:
 227                    case 0x8:
 228                    case 0xE:
 229                    case 0xF:
 230                    case 0x10:
 231                    case 0x11:
 232                    case 0x12:
 233                    case 0x13:
 234                    case 0x14:
 235                    case 0x15:
 236                    case 0x16:
 237                    case 0x17:
 238                    case 0x18:
 239                    case 0x19:
 240                    case 0x1A:
 241                    case 0x1B:
 242                    case 0x1C:
 243                    case 0x1D:
 244                    case 0x1E:
 245                    case 0x1F:
 246                    case 0x27:
 247                    case 0x2D:
 0248                        return 1;
 249                }
 0250            }
 251
 0252            return 0;
 0253        }
 254    }
 255}
 256