Provide info about PDB container type (MSF vs. MSFZ) (#4877)
authorsivadeilra <arlie.davis@gmail.com>
Wed, 21 Aug 2024 18:32:01 +0000 (11:32 -0700)
committerGitHub <noreply@github.com>
Wed, 21 Aug 2024 18:32:01 +0000 (11:32 -0700)
This is a follow-on to my previous PR, #4868 . This allows users of the
`PDBFile` class to query for the "kind" of the container that a given
PDB file uses. Normal (uncompressed) PDBs use a container format called
"MSF". Compressed PDBs use a container format called "MSFZ".

This adds two properties to `PDBFile`. The `ContainerKind` property
returns an enum which allows the caller to distinguish between MSF, and
MSFZ. This also allows for new container formats (as yet unspecified) in
the future. However, the `ContainerKind` enum intentionally does not
distinguish between the version of the container. For that, the
`ContainerKindSpecString` returns a string which contains a textual
identifier ("msf" vs. "msfz") and for MSFZ, a version number. For now,
the only version number defined is 0.

---------

Co-authored-by: Arlie Davis <ardavis@microsoft.com>
src/Microsoft.FileFormats/PDB/IMSFFile.cs
src/Microsoft.FileFormats/PDB/MSFFile.cs
src/Microsoft.FileFormats/PDB/MSFZFile.cs
src/Microsoft.FileFormats/PDB/PDBFile.cs
src/tests/Microsoft.FileFormats.UnitTests/PDB/Tests.cs

index 2c6d4f445f35916bb86a767f15175349fb79bac3..b61502cb13d692316f7758d098cfe5669359ac0d 100644 (file)
@@ -19,5 +19,19 @@ namespace Microsoft.FileFormats.PDB
         /// <param name="stream">The index of the stream. This must be less than NumStreams.</param>
         /// <returns>A Reader which can read the stream.</returns>
         Reader GetStream(uint stream);
+
+        /// <summary>
+        /// Returns the container kind for this implementation.
+        /// </summary>
+        PDBContainerKind ContainerKind { get; }
+
+        /// <summary>
+        /// Returns a string which identifies the container kind, using a backward-compatible naming scheme.
+        /// <summary>
+        /// <para>
+        /// The existing PDB format is identified as "pdb", while PDZ (MSFZ) is identified as "msfz0".
+        /// This allows new versions of MSFZ to be identified and deployed without updating clients of this API.
+        /// </para>
+        public string ContainerKindSpecString { get; }
     }
 }
index 877380e5c4278480772e15cede6760bc2e4fabcc..2118932fe6c560b4071aa2adef34de61cf208143 100644 (file)
@@ -67,5 +67,15 @@ namespace Microsoft.FileFormats.PDB
         {
             return _streams[index];
         }
+
+        public PDBContainerKind ContainerKind
+        {
+            get { return PDBContainerKind.MSF; }
+        }
+
+        public string ContainerKindSpecString
+        {
+            get { return "msf"; }
+        }
     }
 }
index 87089923057ec1d8aa205bfeb8c9f1552f281cbe..8f08437a0d5d96184e0ac3eb7f481ceb592fd762 100644 (file)
@@ -36,13 +36,19 @@ namespace Microsoft.FileFormats.PDB
         /// </summary>
         private readonly uint[] _streamDirStarts;
 
-        private MSFZFile(Reader reader, uint numStreams, uint[] streamDir, uint[] streamDirStarts)
+        /// <summary>
+        /// The value of the "version" field from the MSFZ header.
+        /// </summary>
+        private readonly ulong _msfzVersion;
+
+        private MSFZFile(Reader reader, uint numStreams, uint[] streamDir, uint[] streamDirStarts, ulong msfzVersion)
         {
             Debug.Assert(numStreams == streamDirStarts.Length);
             this._numStreams = numStreams;
             this._reader = reader;
             this._streamDir = streamDir;
             this._streamDirStarts = streamDirStarts;
+            this._msfzVersion = msfzVersion;
         }
 
         public uint NumStreams
@@ -120,6 +126,9 @@ namespace Microsoft.FileFormats.PDB
             uint streamDirSizeCompressed = fileHeader.StreamDirSizeCompressed;
             uint streamDirSizeUncompressed = fileHeader.StreamDirSizeUncompressed;
 
+            // Validate the MSFZ file header version. We keep track of the version in a variable,
+            // even though the only version that is actually supported is V0. This is to minimize
+            // code changes in future versions of this code that would parse V1, V2, etc.
             if (headerVersion != MSFZFileHeader.VersionV0)
             {
                 // Wrong version
@@ -154,7 +163,7 @@ namespace Microsoft.FileFormats.PDB
             // We do not read the Chunk Table because this implementation does not support
             // compression. Since the Chunk Table describes compressed chunks, we will never use it.
 
-            return new MSFZFile(reader, numStreams, streamDirEncoded, streamStarts);
+            return new MSFZFile(reader, numStreams, streamDirEncoded, streamStarts, headerVersion);
         }
 
         /// <summary>
@@ -277,6 +286,15 @@ namespace Microsoft.FileFormats.PDB
             return totalBytesTransferred;
         }
 
+        public PDBContainerKind ContainerKind
+        {
+            get { return PDBContainerKind.MSFZ; }
+        }
+
+        public string ContainerKindSpecString
+        {
+            get { return $"msfz{_msfzVersion}"; }
+        }
 
         public void Dispose()
         {
index cafccb10889f803391cd757ca88f7681e03ad587..a0318664a228c6e3ec5744ca7cc5b21217b69226 100644 (file)
@@ -146,6 +146,34 @@ namespace Microsoft.FileFormats.PDB
             }
             return streamReaders;
         }
+
+        /// <summary>
+        /// Returns the container kind used for this PDB file.
+        /// </summary>
+        public PDBContainerKind ContainerKind
+        {
+            get
+            {
+                CheckValid();
+                return _msfFile.ContainerKind;
+            }
+        }
+
+        /// <summary>
+        /// Returns a string which identifies the container kind, using a backward-compatible naming scheme.
+        /// <summary>
+        /// <para>
+        /// The existing PDB format is identified as "pdb", while PDZ (MSFZ) is identified as "msfz0".
+        /// This allows new versions of MSFZ to be identified and deployed without updating clients of this API.
+        /// </para>
+        public string ContainerKindSpecString
+        {
+            get
+            {
+                CheckValid();
+                return _msfFile.ContainerKindSpecString;
+            }
+        }
     }
 
     /// <summary>
@@ -252,4 +280,20 @@ namespace Microsoft.FileFormats.PDB
 
         public DbiStreamHeader Header { get { _header.Value.IsHeaderValid.CheckThrowing(); return _header.Value; } }
     }
+
+    /// <summary>
+    /// Specifies the kinds of PDB container formats.
+    /// </summary>
+    public enum PDBContainerKind
+    {
+        /// <summary>
+        /// An uncompressed PDB.
+        /// </summary>
+        MSF,
+
+        /// <summary>
+        /// A compressed PDB, also known as a PDBZ or "PDB using MSFZ container".
+        /// </summary>
+        MSFZ,
+    }
 }
index 5a467d2b736d675cadc632aebb5bb398967d273d..e61dc237dc2b55cd71e266c0cb338e4da4826938 100644 (file)
@@ -22,6 +22,9 @@ namespace Microsoft.FileFormats.PDB.Tests
                 Assert.Equal((uint)1, pdb.Age);
                 Assert.Equal(Guid.Parse("99891B3E-D7AE-4C3B-ABFF-8A2B4A9B0C43"), pdb.Signature);
 
+                Assert.Equal(PDBContainerKind.MSF, pdb.ContainerKind);
+                Assert.Equal("msf", pdb.ContainerKindSpecString);
+
                 // Also read the PDBI stream directly, using the downlevel API.
 #pragma warning disable CS0618 // Type or member is obsolete
                 var stream1 = pdb.Streams[1];
@@ -42,6 +45,9 @@ namespace Microsoft.FileFormats.PDB.Tests
                 Assert.Equal((uint)1, pdb.Age);
                 Assert.Equal(Guid.Parse("99891B3E-D7AE-4C3B-ABFF-8A2B4A9B0C43"), pdb.Signature);
 
+                Assert.Equal(PDBContainerKind.MSFZ, pdb.ContainerKind);
+                Assert.Equal("msfz0", pdb.ContainerKindSpecString);
+
                 // Also read the PDBI stream directly, using the downlevel API.
 #pragma warning disable CS0618 // Type or member is obsolete
                 var stream1 = pdb.Streams[1];