// dnlib: See LICENSE.txt for more info using System; using System.Diagnostics; using System.Text; using dnlib.IO; namespace dnlib.DotNet.MD { /// /// A metadata stream header /// [DebuggerDisplay("O:{offset} L:{streamSize} {name}")] public sealed class StreamHeader : FileSection { readonly uint offset; readonly uint streamSize; readonly string name; /// /// The offset of the stream relative to the start of the metadata header /// public uint Offset => offset; /// /// The size of the stream /// public uint StreamSize => streamSize; /// /// The name of the stream /// public string Name => name; /// /// Constructor /// /// PE file reader pointing to the start of this section /// Verify section /// Thrown if verification fails public StreamHeader(ref DataReader reader, bool verify) : this(ref reader, verify, verify, CLRRuntimeReaderKind.CLR, out _) { } internal StreamHeader(ref DataReader reader, bool throwOnError, bool verify, CLRRuntimeReaderKind runtime, out bool failedVerification) { failedVerification = false; SetStartOffset(ref reader); offset = reader.ReadUInt32(); streamSize = reader.ReadUInt32(); name = ReadString(ref reader, 32, verify, ref failedVerification); SetEndoffset(ref reader); if (runtime == CLRRuntimeReaderKind.Mono) { if (offset > reader.Length) offset = reader.Length; // Mono ignores the size (eg. it can be 0 or max value) so set it to the max possible value streamSize = reader.Length - offset; } if (verify && offset + size < offset) failedVerification = true; if (throwOnError && failedVerification) throw new BadImageFormatException("Invalid stream header"); } internal StreamHeader(uint offset, uint streamSize, string name) { this.offset = offset; this.streamSize = streamSize; this.name = name ?? throw new ArgumentNullException(nameof(name)); } static string ReadString(ref DataReader reader, int maxLen, bool verify, ref bool failedVerification) { var origPos = reader.Position; var sb = new StringBuilder(maxLen); int i; for (i = 0; i < maxLen; i++) { byte b = reader.ReadByte(); if (b == 0) break; sb.Append((char)b); } if (verify && i == maxLen) failedVerification = true; if (i != maxLen) reader.Position = origPos + (((uint)i + 1 + 3) & ~3U); return sb.ToString(); } } }