File: System\Reflection\PortableExecutable\DebugDirectory\DebugDirectoryBuilder.EmbeddedPortablePdb.cs
Web Access
Project: src\src\libraries\System.Reflection.Metadata\src\System.Reflection.Metadata.csproj (System.Reflection.Metadata)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Reflection.Metadata;
 
namespace System.Reflection.PortableExecutable
{
    public sealed partial class DebugDirectoryBuilder
    {
        /// <summary>
        /// Adds Embedded Portable PDB entry.
        /// </summary>
        /// <param name="debugMetadata">Portable PDB metadata builder.</param>
        /// <param name="portablePdbVersion">Version of Portable PDB format (e.g. 0x0100 for 1.0).</param>
        /// <exception cref="ArgumentNullException"><paramref name="debugMetadata"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="portablePdbVersion"/> is smaller than 0x0100.</exception>
        public void AddEmbeddedPortablePdbEntry(BlobBuilder debugMetadata, ushort portablePdbVersion)
        {
            if (debugMetadata is null)
            {
                Throw.ArgumentNull(nameof(debugMetadata));
            }
 
            if (portablePdbVersion < PortablePdbVersions.MinFormatVersion)
            {
                Throw.ArgumentOutOfRange(nameof(portablePdbVersion));
            }
 
            int dataSize = WriteEmbeddedPortablePdbData(_dataBuilder, debugMetadata);
 
            AddEntry(
                type: DebugDirectoryEntryType.EmbeddedPortablePdb,
                version: PortablePdbVersions.DebugDirectoryEmbeddedVersion(portablePdbVersion),
                stamp: 0,
                dataSize);
        }
 
        private static int WriteEmbeddedPortablePdbData(BlobBuilder builder, BlobBuilder debugMetadata)
        {
            int start = builder.Count;
 
            // header (signature, decompressed size):
            builder.WriteUInt32(PortablePdbVersions.DebugDirectoryEmbeddedSignature);
            builder.WriteInt32(debugMetadata.Count);
 
            // compressed data:
            using (var deflate = new DeflateStream(new BlobBuilderStream(builder), CompressionLevel.Optimal, leaveOpen: true))
            {
                debugMetadata.WriteContentTo(deflate);
            }
 
            return builder.Count - start;
        }
 
        /// <summary>
        /// Provides a <see cref="Stream"/> interface to write to a <see cref="BlobBuilder"/>.
        /// </summary>
        /// <param name="builder">The blob builder to write data to.</param>
        private sealed class BlobBuilderStream(BlobBuilder builder) : Stream
        {
            public override bool CanRead => false;
            public override bool CanSeek => false;
            public override bool CanWrite => true;
            public override long Length => throw new NotSupportedException();
            public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
            public override void Flush() { }
            public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException();
            public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
            public override void SetLength(long value) => throw new NotSupportedException();
            public override void Write(byte[] buffer, int offset, int count) => builder.WriteBytes(buffer, offset, count);
#if NET
            public override void Write(ReadOnlySpan<byte> buffer) => builder.WriteBytes(buffer);
#endif
        }
    }
}