private int ComputeSizeOfDebugDirectoryData() { // The debug directory data is only needed if this.EmitPdb. return((!EmitPdb) ? 0 : 4 + // 4B signature "RSDS" 16 + // GUID sizeof(uint) + // Age Math.Max(BlobUtilities.GetUTF8ByteCount(PdbPathOpt) + 1, MinPdbPath)); }
/// <summary> /// Writes string in User String (#US) heap format (see ECMA-335-II 24.2.4 #US and #Blob heaps): /// </summary> /// <remarks> /// The string is UTF16 encoded and prefixed by the its size in bytes. /// /// This final byte holds the value 1 if and only if any UTF16 character within the string has any bit set in its top byte, /// or its low byte is any of the following: 0x01–0x08, 0x0E–0x1F, 0x27, 0x2D, 0x7F. Otherwise, it holds 0. /// The 1 signifies Unicode characters that require handling beyond that normally provided for 8-bit encoding sets. /// </remarks> /// <exception cref="InvalidOperationException">Builder is not writable, it has been linked with another one.</exception> public void WriteUserString(string value) { if (value == null) { throw new ArgumentNullException(nameof(value)); } WriteCompressedInteger(BlobUtilities.GetUserStringByteLength(BlobUtilities.GetUTF8ByteCount(value))); WriteUTF8(value, false); WriteByte(BlobUtilities.GetUserStringTrailingByte(value)); }
private void TestGetUTF8ByteCount(int expectedCount, string expectedRemainder, string str, int charCount, int byteLimit) { fixed(char *ptr = str) { char *remainderPtr; Assert.Equal(expectedCount, BlobUtilities.GetUTF8ByteCount(ptr, charCount, byteLimit, out remainderPtr)); string remainder = new string(remainderPtr); Assert.Equal(expectedRemainder, remainder); } }
private void WriteUTF8(string str, int start, int length, bool allowUnpairedSurrogates, bool prependSize) { fixed (char* strPtr = str) { char* charPtr = strPtr + start; int byteCount = BlobUtilities.GetUTF8ByteCount(charPtr, length); if (prependSize) { WriteCompressedInteger(byteCount); } int startOffset = Advance(byteCount); _buffer.WriteUTF8(startOffset, charPtr, length, byteCount, allowUnpairedSurrogates); } }
/// <summary> /// Creates a builder of a metadata root. /// </summary> /// <param name="tablesAndHeaps"> /// Builder populated with metadata entities stored in tables and values stored in heaps. /// The entities and values will be enumerated when serializing the metadata root. /// </param> /// <param name="metadataVersion"> /// The version string written to the metadata header. The default value is "v4.0.30319". /// </param> /// <exception cref="ArgumentNullException"><paramref name="tablesAndHeaps"/> is null.</exception> /// <exception cref="ArgumentException"><paramref name="metadataVersion"/> is too long (the number of bytes when UTF8-encoded must be less than 255).</exception> public MetadataRootBuilder(MetadataBuilder tablesAndHeaps, string metadataVersion = null) { if (tablesAndHeaps == null) { Throw.ArgumentNull(nameof(tablesAndHeaps)); } Debug.Assert(BlobUtilities.GetUTF8ByteCount(DefaultMetadataVersionString) == DefaultMetadataVersionString.Length); int metadataVersionByteCount = metadataVersion != null?BlobUtilities.GetUTF8ByteCount(metadataVersion) : DefaultMetadataVersionString.Length; if (metadataVersionByteCount > MetadataSizes.MaxMetadataVersionByteCount) { Throw.InvalidArgument(SR.MetadataVersionTooLong, nameof(metadataVersion)); } _tablesAndHeaps = tablesAndHeaps; MetadataVersion = metadataVersion ?? DefaultMetadataVersionString; _serializedMetadata = tablesAndHeaps.GetSerializedMetadata(EmptyRowCounts, metadataVersionByteCount, isStandaloneDebugMetadata: false); }
internal unsafe void WriteUTF8(string str, int start, int length, bool allowUnpairedSurrogates, bool prependSize) { Debug.Assert(start >= 0); Debug.Assert(length >= 0); Debug.Assert(start + length <= str.Length); if (!IsHead) { Throw.InvalidOperationBuilderAlreadyLinked(); } fixed(char *strPtr = str) { char *currentPtr = strPtr + start; char *nextPtr; // the max size of compressed int is 4B: int byteLimit = FreeBytes - (prependSize ? sizeof(uint) : 0); int bytesToCurrent = BlobUtilities.GetUTF8ByteCount(currentPtr, length, byteLimit, out nextPtr); int charsToCurrent = (int)(nextPtr - currentPtr); int charsToNext = length - charsToCurrent; int bytesToNext = BlobUtilities.GetUTF8ByteCount(nextPtr, charsToNext); if (prependSize) { WriteCompressedInteger(bytesToCurrent + bytesToNext); } _buffer.WriteUTF8(Length, currentPtr, charsToCurrent, bytesToCurrent, allowUnpairedSurrogates); AddLength(bytesToCurrent); if (bytesToNext > 0) { Expand(bytesToNext); _buffer.WriteUTF8(0, nextPtr, charsToNext, bytesToNext, allowUnpairedSurrogates); AddLength(bytesToNext); } } }
/// <summary> /// Creates a builder of a Portable PDB image. /// </summary> /// <param name="tablesAndHeaps"> /// Builder populated with debug metadata entities stored in tables and values stored in heaps. /// The entities and values will be enumerated when serializing the Portable PDB image. /// </param> /// <param name="typeSystemRowCounts"> /// Row counts of all tables that the associated type-system metadata contain. /// Each slot in the array corresponds to a table (<see cref="TableIndex"/>). /// The length of the array must be equal to <see cref="MetadataTokens.TableCount"/>. /// </param> /// <param name="entryPoint"> /// Entry point method definition handle. /// </param> /// <param name="idProvider"> /// Function calculating id of content represented as a sequence of blobs. /// If not specified a default function that ignores the content and returns current time-based content id is used /// (<see cref="BlobContentId.GetTimeBasedProvider()"/>). /// You must specify a deterministic function to produce a deterministic Portable PDB image. /// </param> /// <exception cref="ArgumentNullException"><paramref name="tablesAndHeaps"/> or <paramref name="typeSystemRowCounts"/> is null.</exception> public PortablePdbBuilder( MetadataBuilder tablesAndHeaps, ImmutableArray <int> typeSystemRowCounts, MethodDefinitionHandle entryPoint, Func <IEnumerable <Blob>, BlobContentId>?idProvider = null) { if (tablesAndHeaps == null) { Throw.ArgumentNull(nameof(tablesAndHeaps)); } ValidateTypeSystemRowCounts(typeSystemRowCounts); _builder = tablesAndHeaps; _entryPoint = entryPoint; Debug.Assert(BlobUtilities.GetUTF8ByteCount(MetadataVersion) == MetadataVersion.Length); _serializedMetadata = tablesAndHeaps.GetSerializedMetadata(typeSystemRowCounts, MetadataVersion.Length, isStandaloneDebugMetadata: true); IdProvider = idProvider ?? BlobContentId.GetTimeBasedProvider(); }
private void WriteUTF8(string str, int start, int length, bool allowUnpairedSurrogates, bool prependSize) { if (!IsHead) { ThrowHeadRequired(); } fixed(char *strPtr = str) { char *currentPtr = strPtr + start; char *nextPtr; // the max size of compressed int is 4B: int byteLimit = FreeBytes - (prependSize ? sizeof(uint) : 0); int bytesToCurrent = BlobUtilities.GetUTF8ByteCount(currentPtr, length, byteLimit, out nextPtr); int charsToCurrent = (int)(nextPtr - currentPtr); int charsToNext = str.Length - charsToCurrent; int bytesToNext = BlobUtilities.GetUTF8ByteCount(nextPtr, charsToNext); if (prependSize) { WriteCompressedInteger(bytesToCurrent + bytesToNext); } _buffer.WriteUTF8(Length, currentPtr, charsToCurrent, bytesToCurrent, allowUnpairedSurrogates); AddLength(bytesToCurrent); if (bytesToNext > 0) { Expand(bytesToNext); _buffer.WriteUTF8(0, nextPtr, charsToNext, bytesToNext, allowUnpairedSurrogates); AddLength(bytesToNext); } } }
/// <summary> /// Fills in stringIndexMap with data from stringIndex and write to stringWriter. /// Releases stringIndex as the stringTable is sealed after this point. /// </summary> private void SerializeStringHeap() { // Sort by suffix and remove stringIndex var sorted = new List <KeyValuePair <string, StringHandle> >(_strings); sorted.Sort(new SuffixSort()); _strings = null; _stringWriter = new BlobBuilder(1024); // Create VirtIdx to Idx map and add entry for empty string _stringIndexToResolvedOffsetMap = new int[sorted.Count + 1]; _stringIndexToResolvedOffsetMap[0] = 0; _stringWriter.WriteByte(0); // Find strings that can be folded string prev = string.Empty; foreach (KeyValuePair <string, StringHandle> entry in sorted) { int position = _stringHeapStartOffset + _stringWriter.Position; // It is important to use ordinal comparison otherwise we'll use the current culture! if (prev.EndsWith(entry.Key, StringComparison.Ordinal) && !BlobUtilities.IsLowSurrogateChar(entry.Key[0])) { // Map over the tail of prev string. Watch for null-terminator of prev string. _stringIndexToResolvedOffsetMap[MetadataTokens.GetHeapOffset(entry.Value)] = position - (BlobUtilities.GetUTF8ByteCount(entry.Key) + 1); } else { _stringIndexToResolvedOffsetMap[MetadataTokens.GetHeapOffset(entry.Value)] = position; _stringWriter.WriteUTF8(entry.Key, allowUnpairedSurrogates: false); _stringWriter.WriteByte(0); } prev = entry.Key; } }
/// <summary> /// Fills in stringIndexMap with data from stringIndex and write to stringWriter. /// Releases stringIndex as the stringTable is sealed after this point. /// </summary> private static ImmutableArray <int> SerializeStringHeap( BlobBuilder heapBuilder, Dictionary <string, StringHandle> strings, int stringHeapStartOffset) { // Sort by suffix and remove stringIndex var sorted = new List <KeyValuePair <string, StringHandle> >(strings); sorted.Sort(SuffixSort.Instance); // Create VirtIdx to Idx map and add entry for empty string int totalCount = sorted.Count + 1; var stringVirtualIndexToHeapOffsetMap = ImmutableArray.CreateBuilder <int>(totalCount); stringVirtualIndexToHeapOffsetMap.Count = totalCount; stringVirtualIndexToHeapOffsetMap[0] = 0; heapBuilder.WriteByte(0); // Find strings that can be folded string prev = string.Empty; foreach (KeyValuePair <string, StringHandle> entry in sorted) { int position = stringHeapStartOffset + heapBuilder.Count; // It is important to use ordinal comparison otherwise we'll use the current culture! if (prev.EndsWith(entry.Key, StringComparison.Ordinal) && !BlobUtilities.IsLowSurrogateChar(entry.Key[0])) { // Map over the tail of prev string. Watch for null-terminator of prev string. stringVirtualIndexToHeapOffsetMap[entry.Value.GetWriterVirtualIndex()] = position - (BlobUtilities.GetUTF8ByteCount(entry.Key) + 1); } else { stringVirtualIndexToHeapOffsetMap[entry.Value.GetWriterVirtualIndex()] = position; heapBuilder.WriteUTF8(entry.Key, allowUnpairedSurrogates: false); heapBuilder.WriteByte(0); } prev = entry.Key; } return(stringVirtualIndexToHeapOffsetMap.MoveToImmutable()); }