< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 64
Coverable lines: 64
Total lines: 135
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 14
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%220%
ReadBytes(...)100%110%
ReadByte()100%110%
ReadInt16()100%110%
ReadUInt16()100%110%
ReadInt32()100%110%
ReadUInt32()100%110%
ReadUInt64()100%110%
ReadNullPaddedUTF8(...)0%440%
CheckBounds(...)0%440%
CheckBounds(...)0%440%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEBinaryReader.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.Diagnostics;
 5using System.IO;
 6using System.Reflection.Metadata;
 7using System.Runtime.CompilerServices;
 8using System.Text;
 9
 10namespace System.Reflection.PortableExecutable
 11{
 12    /// <summary>
 13    /// Simple BinaryReader wrapper to:
 14    ///
 15    ///  1) throw BadImageFormat instead of EndOfStream or ArgumentOutOfRange.
 16    ///  2) limit reads to a subset of the base stream.
 17    ///
 18    /// Only methods that are needed to read PE headers are implemented.
 19    /// </summary>
 20    internal readonly struct PEBinaryReader
 21    {
 22        private readonly long _startOffset;
 23        private readonly long _maxOffset;
 24        private readonly BinaryReader _reader;
 25
 26        public PEBinaryReader(Stream stream, int size)
 027        {
 028            Debug.Assert(size >= 0 && size <= (stream.Length - stream.Position));
 29
 030            _startOffset = stream.Position;
 031            _maxOffset = _startOffset + size;
 032            _reader = new BinaryReader(stream, Encoding.UTF8, leaveOpen: true);
 033        }
 34
 35        public int Offset
 36        {
 037            get { return (int)(_reader.BaseStream.Position - _startOffset); }
 38            set
 039            {
 040                CheckBounds(_startOffset, value);
 041                _reader.BaseStream.Seek(_startOffset + value, SeekOrigin.Begin);
 042            }
 43        }
 44
 45        private byte[] ReadBytes(int count)
 046        {
 047            CheckBounds(_reader.BaseStream.Position, count);
 048            return _reader.ReadBytes(count);
 049        }
 50
 51        public byte ReadByte()
 052        {
 053            CheckBounds(sizeof(byte));
 054            return _reader.ReadByte();
 055        }
 56
 57        public short ReadInt16()
 058        {
 059            CheckBounds(sizeof(short));
 060            return _reader.ReadInt16();
 061        }
 62
 63        public ushort ReadUInt16()
 064        {
 065            CheckBounds(sizeof(ushort));
 066            return _reader.ReadUInt16();
 067        }
 68
 69        public int ReadInt32()
 070        {
 071            CheckBounds(sizeof(int));
 072            return _reader.ReadInt32();
 073        }
 74
 75        public uint ReadUInt32()
 076        {
 077            CheckBounds(sizeof(uint));
 078            return _reader.ReadUInt32();
 079        }
 80
 81        public ulong ReadUInt64()
 082        {
 083            CheckBounds(sizeof(ulong));
 084            return _reader.ReadUInt64();
 085        }
 86
 87        /// <summary>
 88        /// Reads a fixed-length byte block as a null-padded UTF-8 encoded string.
 89        /// The padding is not included in the returned string.
 90        ///
 91        /// Note that it is legal for UTF-8 strings to contain NUL; if NUL occurs
 92        /// between non-NUL codepoints, it is not considered to be padding and
 93        /// is included in the result.
 94        /// </summary>
 95        public string ReadNullPaddedUTF8(int byteCount)
 096        {
 097            byte[] bytes = ReadBytes(byteCount);
 098            int nonPaddedLength = 0;
 099            for (int i = bytes.Length; i > 0; --i)
 0100            {
 0101                if (bytes[i - 1] != 0)
 0102                {
 0103                    nonPaddedLength = i;
 0104                    break;
 105                }
 0106            }
 0107            return Encoding.UTF8.GetString(bytes, 0, nonPaddedLength);
 0108        }
 109
 110        private void CheckBounds(uint count)
 0111        {
 0112            Debug.Assert(count <= sizeof(long));  // Error message assumes we're trying to read constant small number of
 0113            Debug.Assert(_reader.BaseStream.Position >= 0 && _maxOffset >= 0);
 114
 115            // Add cannot overflow because the worst case is (ulong)long.MaxValue + uint.MaxValue < ulong.MaxValue.
 0116            if ((ulong)_reader.BaseStream.Position + count > (ulong)_maxOffset)
 0117            {
 0118                Throw.ImageTooSmall();
 119            }
 0120        }
 121
 122        private void CheckBounds(long startPosition, int count)
 0123        {
 0124            Debug.Assert(startPosition >= 0 && _maxOffset >= 0);
 125
 126            // Add cannot overflow because the worst case is (ulong)long.MaxValue + uint.MaxValue < ulong.MaxValue.
 127            // Negative count is handled by overflow to greater than maximum size = int.MaxValue.
 0128            if ((ulong)startPosition + unchecked((uint)count) > (ulong)_maxOffset)
 0129            {
 0130                Throw.ImageTooSmallOrContainsInvalidOffsetOrCount();
 131            }
 0132        }
 133    }
 134}
 135