Beispiel #1
0
        public void WriteUTF8()
        {
            var writer = new BlobBuilder(4);

            writer.WriteUTF8("a");
            writer.WriteUTF8("");
            writer.WriteUTF8("bc");
            writer.WriteUTF8("d");
            writer.WriteUTF8("");

            writer.WriteUTF8(Encoding.UTF8.GetString(new byte[]
            {
                0x00,
                0xC2, 0x80,
                0xE1, 0x88, 0xB4
            }));

            writer.WriteUTF8("\0\ud800");       // hi surrogate
            writer.WriteUTF8("\0\udc00");       // lo surrogate
            writer.WriteUTF8("\0\ud800\udc00"); // pair
            writer.WriteUTF8("\0\udc00\ud800"); // lo + hi

            AssertEx.Equal(new byte[]
            {
                (byte)'a',
                (byte)'b', (byte)'c',
                (byte)'d',
                0x00, 0xC2, 0x80, 0xE1, 0x88, 0xB4,

                0x00, 0xED, 0xA0, 0x80,
                0x00, 0xED, 0xB0, 0x80,
                0x00, 0xF0, 0x90, 0x80, 0x80,
                0x00, 0xED, 0xB0, 0x80, 0xED, 0xA0, 0x80
            }, writer.ToArray());
        }
Beispiel #2
0
        public unsafe void Write_Errors()
        {
            var builder = new BlobBuilder(16);

            Assert.Throws <ArgumentNullException>(() => builder.WriteUTF16((char[])null));
            Assert.Throws <ArgumentNullException>(() => builder.WriteUTF16((string)null));
            Assert.Throws <ArgumentNullException>(() => builder.WriteUTF8(null, allowUnpairedSurrogates: true));
            Assert.Throws <ArgumentNullException>(() => builder.WriteUTF8(null, allowUnpairedSurrogates: true));
            Assert.Throws <ArgumentNullException>(() => builder.TryWriteBytes((Stream)null, 0));
            Assert.Throws <ArgumentNullException>(() => builder.WriteBytes(null));
            Assert.Throws <ArgumentNullException>(() => builder.WriteBytes(null, 0, 0));
            Assert.Throws <ArgumentNullException>(() => builder.WriteBytes((byte *)null, 0));
            Assert.Throws <ArgumentNullException>(() => builder.WriteBytes(default(ImmutableArray <byte>)));
            Assert.Throws <ArgumentNullException>(() => builder.WriteBytes(default(ImmutableArray <byte>), 0, 0));

            var bw = default(BlobWriter);

            Assert.Throws <ArgumentNullException>(() => builder.WriteContentTo(ref bw));
            Assert.Throws <ArgumentNullException>(() => builder.WriteContentTo((Stream)null));
            Assert.Throws <ArgumentNullException>(() => builder.WriteContentTo((BlobBuilder)null));

            Assert.Throws <ArgumentOutOfRangeException>(() => builder.TryWriteBytes(new MemoryStream(), -1));
            Assert.Throws <ArgumentOutOfRangeException>(() => builder.WriteBytes(0, -1));
            Assert.Throws <ArgumentOutOfRangeException>(() => builder.WriteBytes(new byte[] { }, 1, 0));
            Assert.Throws <ArgumentOutOfRangeException>(() => builder.WriteBytes(new byte[] { }, 0, 1));
            Assert.Throws <ArgumentOutOfRangeException>(() => builder.WriteBytes(new byte[] { }, 0, -1));
            Assert.Throws <ArgumentOutOfRangeException>(() => builder.WriteBytes(ImmutableArray <byte> .Empty, 1, 0));
            Assert.Throws <ArgumentOutOfRangeException>(() => builder.WriteBytes(ImmutableArray <byte> .Empty, 0, 1));
            Assert.Throws <ArgumentOutOfRangeException>(() => builder.WriteBytes(ImmutableArray <byte> .Empty, 1, -1));
        }
Beispiel #3
0
        public void WriteUTF8_ReplaceUnpairedSurrogates()
        {
            var writer = new BlobBuilder(4);

            writer.WriteUTF8("a", allowUnpairedSurrogates: false);
            writer.WriteUTF8("", allowUnpairedSurrogates: false);
            writer.WriteUTF8("bc", allowUnpairedSurrogates: false);
            writer.WriteUTF8("d", allowUnpairedSurrogates: false);
            writer.WriteUTF8("", allowUnpairedSurrogates: false);

            writer.WriteUTF8(Encoding.UTF8.GetString(new byte[]
            {
                0x00,
                0xC2, 0x80,
                0xE1, 0x88, 0xB4
            }), allowUnpairedSurrogates: false);

            writer.WriteUTF8("\0\ud800", allowUnpairedSurrogates: false);       // hi surrogate
            writer.WriteUTF8("\0\udc00", allowUnpairedSurrogates: false);       // lo surrogate
            writer.WriteUTF8("\0\ud800\udc00", allowUnpairedSurrogates: false); // pair
            writer.WriteUTF8("\0\udc00\ud800", allowUnpairedSurrogates: false); // lo + hi

            AssertEx.Equal(new byte[]
            {
                (byte)'a',
                (byte)'b', (byte)'c',
                (byte)'d',
                0x00, 0xC2, 0x80, 0xE1, 0x88, 0xB4,

                0x00, 0xEF, 0xBF, 0xBD,
                0x00, 0xEF, 0xBF, 0xBD,
                0x00, 0xF0, 0x90, 0x80, 0x80,
                0x00, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD
            }, writer.ToArray());
        }
Beispiel #4
0
        // Copied from Roslyn: MetadataWriter.SerializeTupleElementNames
        internal static void SerializeTupleElementNames(BlobBuilder builder, ImmutableArray <string> names)
        {
            foreach (var name in names)
            {
                if (name != null)
                {
                    builder.WriteUTF8(name);
                }

                builder.WriteByte(0);
            }
        }
        private static int WritePdbChecksumData(BlobBuilder builder, string algorithmName, ImmutableArray <byte> checksum)
        {
            int start = builder.Count;

            // NUL-terminated algorithm name:
            builder.WriteUTF8(algorithmName, allowUnpairedSurrogates: true);
            builder.WriteByte(0);

            // checksum:
            builder.WriteBytes(checksum);

            return(builder.Count - start);
        }
        private BlobHandle GetCustomAttributeValueFromString(string str)
        {
            if (str == null)
            {
                return(default(BlobHandle));
            }

            var builder = new BlobBuilder();

            builder.WriteBytes(new byte[] { 0x01, 0x00 }); // "prolog"
            builder.WriteUTF8(str);

            return(GetBlob(builder));
        }
Beispiel #7
0
        public void Link()
        {
            var builder1 = new BlobBuilder(16);

            builder1.WriteByte(1);

            var builder2 = new BlobBuilder(16);

            builder2.WriteByte(2);

            var builder3 = new BlobBuilder(16);

            builder3.WriteByte(3);

            var builder4 = new BlobBuilder(16);

            builder4.WriteByte(4);

            var builder5 = new BlobBuilder(16);

            builder5.WriteByte(5);

            builder2.LinkPrefix(builder1);
            AssertEx.Equal(new byte[] { 1, 2 }, builder2.ToArray());
            Assert.Throws <InvalidOperationException>(() => builder1.ToArray());
            Assert.Throws <InvalidOperationException>(() => builder2.LinkPrefix(builder1));
            Assert.Throws <InvalidOperationException>(() => builder1.WriteByte(0xff));
            Assert.Throws <InvalidOperationException>(() => builder1.WriteBytes(1, 10));
            Assert.Throws <InvalidOperationException>(() => builder1.WriteBytes(new byte[] { 1 }));
            Assert.Throws <InvalidOperationException>(() => builder1.ReserveBytes(1));
            Assert.Throws <InvalidOperationException>(() => builder1.GetBlobs());
            Assert.Throws <InvalidOperationException>(() => builder1.ContentEquals(builder1));
            Assert.Throws <InvalidOperationException>(() => builder1.WriteUTF16("str"));
            Assert.Throws <InvalidOperationException>(() => builder1.WriteUTF8("str", allowUnpairedSurrogates: false));

            builder2.LinkSuffix(builder3);
            AssertEx.Equal(new byte[] { 1, 2, 3 }, builder2.ToArray());
            Assert.Throws <InvalidOperationException>(() => builder3.LinkPrefix(builder5));

            builder2.LinkPrefix(builder4);
            AssertEx.Equal(new byte[] { 4, 1, 2, 3 }, builder2.ToArray());
            Assert.Throws <InvalidOperationException>(() => builder4.LinkPrefix(builder5));

            builder2.LinkSuffix(builder5);
            AssertEx.Equal(new byte[] { 4, 1, 2, 3, 5 }, builder2.ToArray());
        }
        /// <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());
        }
Beispiel #9
0
        private static int WriteCodeViewData(BlobBuilder builder, string pdbPath, Guid pdbGuid, int age)
        {
            int start = builder.Count;

            builder.WriteByte((byte)'R');
            builder.WriteByte((byte)'S');
            builder.WriteByte((byte)'D');
            builder.WriteByte((byte)'S');

            // PDB id:
            builder.WriteGuid(pdbGuid);

            // age
            builder.WriteInt32(age);

            // UTF-8 encoded zero-terminated path to PDB
            builder.WriteUTF8(pdbPath, allowUnpairedSurrogates: true);
            builder.WriteByte(0);

            return(builder.Count - start);
        }
        /// <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;
            }
        }
        public void WriteUTF8_Substring()
        {
            var writer = new BlobBuilder(4);

            writer.WriteUTF8("abc", 0, 0, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new byte[0], writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 0, 1, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new[] { (byte)'a' }, writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 0, 2, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new[] { (byte)'a', (byte)'b' }, writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 0, 3, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new[] { (byte)'a', (byte)'b', (byte)'c' }, writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 1, 0, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new byte[0], writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 1, 1, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new[] { (byte)'b' }, writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 1, 2, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new[] { (byte)'b', (byte)'c' }, writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 2, 1, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new[] { (byte)'c' }, writer.ToArray());
            writer.Clear();
        }
Beispiel #12
0
        public void WriteUTF8_ReplaceUnpairedSurrogates()
        {
            var writer = new BlobBuilder(4);
            writer.WriteUTF8("a", allowUnpairedSurrogates: false);
            writer.WriteUTF8("", allowUnpairedSurrogates: false);
            writer.WriteUTF8("bc", allowUnpairedSurrogates: false);
            writer.WriteUTF8("d", allowUnpairedSurrogates: false);
            writer.WriteUTF8("", allowUnpairedSurrogates: false);

            writer.WriteUTF8(Encoding.UTF8.GetString(new byte[]
            {
                0x00,
                0xC2, 0x80,
                0xE1, 0x88, 0xB4
            }), allowUnpairedSurrogates: false);

            writer.WriteUTF8("\0\ud800", allowUnpairedSurrogates: false);       // hi surrogate
            writer.WriteUTF8("\0\udc00", allowUnpairedSurrogates: false);       // lo surrogate
            writer.WriteUTF8("\0\ud800\udc00", allowUnpairedSurrogates: false); // pair
            writer.WriteUTF8("\0\udc00\ud800", allowUnpairedSurrogates: false); // lo + hi

            AssertEx.Equal(new byte[]
            {
                (byte)'a',
                (byte)'b', (byte)'c',
                (byte)'d',
                0x00, 0xC2, 0x80, 0xE1, 0x88, 0xB4,

                0x00, 0xEF, 0xBF, 0xBD,
                0x00, 0xEF, 0xBF, 0xBD,
                0x00, 0xF0, 0x90, 0x80, 0x80,
                0x00, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD
            }, writer.ToArray());
        }
Beispiel #13
0
        /// <summary>
        /// Serialize the export symbol table into the export section.
        /// </summary>
        /// <param name="location">RVA and file location of the .edata section</param>
        private BlobBuilder SerializeExportSection(SectionLocation sectionLocation)
        {
            _exportSymbols.MergeSort((es1, es2) => StringComparer.Ordinal.Compare(es1.Name, es2.Name));

            BlobBuilder builder = new BlobBuilder();

            int minOrdinal = int.MaxValue;
            int maxOrdinal = int.MinValue;

            // First, emit the name table and store the name RVA's for the individual export symbols
            // Also, record the ordinal range.
            foreach (ExportSymbol symbol in _exportSymbols)
            {
                symbol.NameRVAWhenPlaced = sectionLocation.RelativeVirtualAddress + builder.Count;
                builder.WriteUTF8(symbol.Name);
                builder.WriteByte(0);

                if (symbol.Ordinal < minOrdinal)
                {
                    minOrdinal = symbol.Ordinal;
                }
                if (symbol.Ordinal > maxOrdinal)
                {
                    maxOrdinal = symbol.Ordinal;
                }
            }

            // Emit the DLL name
            int dllNameRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            builder.WriteUTF8(_dllNameForExportDirectoryTable);
            builder.WriteByte(0);

            int[] addressTable = new int[maxOrdinal - minOrdinal + 1];

            // Emit the name pointer table; it should be alphabetically sorted.
            // Also, we can now fill in the export address table as we've detected its size
            // in the previous pass.
            int namePointerTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            foreach (ExportSymbol symbol in _exportSymbols)
            {
                builder.WriteInt32(symbol.NameRVAWhenPlaced);
                SymbolTarget symbolTarget  = _symbolMap[symbol.Symbol];
                Section      symbolSection = _sections[symbolTarget.SectionIndex];
                Debug.Assert(symbolSection.RVAWhenPlaced != 0);
                addressTable[symbol.Ordinal - minOrdinal] = symbolSection.RVAWhenPlaced + symbolTarget.Offset;
            }

            // Emit the ordinal table
            int ordinalTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            foreach (ExportSymbol symbol in _exportSymbols)
            {
                builder.WriteUInt16((ushort)(symbol.Ordinal - minOrdinal));
            }

            // Emit the address table
            int addressTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            foreach (int addressTableEntry in addressTable)
            {
                builder.WriteInt32(addressTableEntry);
            }

            // Emit the export directory table
            int exportDirectoryTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            // +0x00: reserved
            builder.WriteInt32(0);
            // +0x04: TODO: time/date stamp
            builder.WriteInt32(0);
            // +0x08: major version
            builder.WriteInt16(0);
            // +0x0A: minor version
            builder.WriteInt16(0);
            // +0x0C: DLL name RVA
            builder.WriteInt32(dllNameRVA);
            // +0x10: ordinal base
            builder.WriteInt32(minOrdinal);
            // +0x14: number of entries in the address table
            builder.WriteInt32(addressTable.Length);
            // +0x18: number of name pointers
            builder.WriteInt32(_exportSymbols.Count);
            // +0x1C: export address table RVA
            builder.WriteInt32(addressTableRVA);
            // +0x20: name pointer RVV
            builder.WriteInt32(namePointerTableRVA);
            // +0x24: ordinal table RVA
            builder.WriteInt32(ordinalTableRVA);
            int exportDirectorySize = sectionLocation.RelativeVirtualAddress + builder.Count - exportDirectoryTableRVA;

            _exportDirectoryEntry = new DirectoryEntry(relativeVirtualAddress: exportDirectoryTableRVA, size: exportDirectorySize);

            return(builder);
        }
Beispiel #14
0
        private readonly static byte[] zeroStamp = new byte[4]; // four bytes of zero

        /// <summary>
        /// Write the entire "Debug Directory (Image Only)" along with data that it points to.
        /// </summary>
        internal void WriteDebugTable(BlobBuilder builder, PESectionLocation textSectionLocation, ContentId nativePdbContentId, ContentId portablePdbContentId)
        {
            Debug.Assert(builder.Count == 0);

            int tableSize = ImageDebugDirectoryBaseSize;

            Debug.Assert(tableSize != 0);
            Debug.Assert(nativePdbContentId.IsDefault || portablePdbContentId.IsDefault);
            Debug.Assert(!EmitPdb || (nativePdbContentId.IsDefault ^ portablePdbContentId.IsDefault));

            int dataSize = ComputeSizeOfDebugDirectoryData();

            if (EmitPdb)
            {
                const int IMAGE_DEBUG_TYPE_CODEVIEW = 2; // from PE spec
                uint      dataOffset = (uint)(ComputeOffsetToDebugTable() + tableSize);
                WriteDebugTableEntry(builder,
                                     stamp: nativePdbContentId.Stamp ?? portablePdbContentId.Stamp,
                                     version: portablePdbContentId.IsDefault ? (uint)0 : ('P' << 24 | 'M' << 16 | 0x01 << 8 | 0x00),
                                     debugType: IMAGE_DEBUG_TYPE_CODEVIEW,
                                     sizeOfData: (uint)dataSize,
                                     addressOfRawData: (uint)textSectionLocation.RelativeVirtualAddress + dataOffset, // RVA of the data
                                     pointerToRawData: (uint)textSectionLocation.PointerToRawData + dataOffset);      // position of the data in the PE stream
            }

            if (IsDeterministic)
            {
                const int IMAGE_DEBUG_TYPE_NO_TIMESTAMP = 16; // from PE spec
                WriteDebugTableEntry(builder,
                                     stamp: zeroStamp,
                                     version: 0,
                                     debugType: IMAGE_DEBUG_TYPE_NO_TIMESTAMP,
                                     sizeOfData: 0,
                                     addressOfRawData: 0,
                                     pointerToRawData: 0);
            }

            // We should now have written all and precisely the data we said we'd write for the table entries.
            Debug.Assert(builder.Count == tableSize);

            // ====================
            // The following is additional data beyond the debug directory at the offset `dataOffset`
            // pointed to by the ImageDebugTypeCodeView entry.

            if (EmitPdb)
            {
                builder.WriteByte((byte)'R');
                builder.WriteByte((byte)'S');
                builder.WriteByte((byte)'D');
                builder.WriteByte((byte)'S');

                // PDB id:
                builder.WriteBytes(nativePdbContentId.Guid ?? portablePdbContentId.Guid);

                // age
                builder.WriteUInt32(1); // TODO: allow specify for native PDBs

                // UTF-8 encoded zero-terminated path to PDB
                int pathStart = builder.Count;
                builder.WriteUTF8(PdbPathOpt, allowUnpairedSurrogates: true);
                builder.WriteByte(0);

                // padding:
                builder.WriteBytes(0, Math.Max(0, MinPdbPath - (builder.Count - pathStart)));
            }

            // We should now have written all and precisely the data we said we'd write for the table and its data.
            Debug.Assert(builder.Count == tableSize + dataSize);
        }
 /// <summary>
 /// Write string as UTF8 with null terminator.
 /// </summary>
 private static void WriteUtf8String(BlobBuilder builder, string str)
 {
     builder.WriteUTF8(str);
     builder.WriteByte(0);
 }
Beispiel #16
0
        public void Link()
        {
            var builder1 = new BlobBuilder(16);
            builder1.WriteByte(1);

            var builder2 = new BlobBuilder(16);
            builder2.WriteByte(2);

            var builder3 = new BlobBuilder(16);
            builder3.WriteByte(3);

            var builder4 = new BlobBuilder(16);
            builder4.WriteByte(4);

            var builder5 = new BlobBuilder(16);
            builder5.WriteByte(5);

            builder2.LinkPrefix(builder1);
            AssertEx.Equal(new byte[] { 1, 2 }, builder2.ToArray());
            Assert.Throws<InvalidOperationException>(() => builder1.ToArray());
            Assert.Throws<InvalidOperationException>(() => builder2.LinkPrefix(builder1));
            Assert.Throws<InvalidOperationException>(() => builder1.WriteByte(0xff));
            Assert.Throws<InvalidOperationException>(() => builder1.WriteBytes(1, 10));
            Assert.Throws<InvalidOperationException>(() => builder1.WriteBytes(new byte[] { 1 }));
            Assert.Throws<InvalidOperationException>(() => builder1.ReserveBytes(1));
            Assert.Throws<InvalidOperationException>(() => builder1.GetBlobs());
            Assert.Throws<InvalidOperationException>(() => builder1.ContentEquals(builder1));
            Assert.Throws<InvalidOperationException>(() => builder1.WriteUTF16("str"));
            Assert.Throws<InvalidOperationException>(() => builder1.WriteUTF8("str", allowUnpairedSurrogates: false));

            builder2.LinkSuffix(builder3);
            AssertEx.Equal(new byte[] { 1, 2, 3 }, builder2.ToArray());
            Assert.Throws<InvalidOperationException>(() => builder3.LinkPrefix(builder5));

            builder2.LinkPrefix(builder4);
            AssertEx.Equal(new byte[] { 4, 1, 2, 3 }, builder2.ToArray());
            Assert.Throws<InvalidOperationException>(() => builder4.LinkPrefix(builder5));

            builder2.LinkSuffix(builder5);
            AssertEx.Equal(new byte[] { 4, 1, 2, 3, 5 }, builder2.ToArray());
        }
Beispiel #17
0
        public unsafe void Write_Errors()
        {
            var builder = new BlobBuilder(16);
            Assert.Throws<ArgumentNullException>(() => builder.WriteUTF16((char[])null));
            Assert.Throws<ArgumentNullException>(() => builder.WriteUTF16((string)null));
            Assert.Throws<ArgumentNullException>(() => builder.WriteUTF8(null, allowUnpairedSurrogates: true));
            Assert.Throws<ArgumentNullException>(() => builder.WriteUTF8(null, allowUnpairedSurrogates: true));
            Assert.Throws<ArgumentNullException>(() => builder.TryWriteBytes((Stream)null, 0));
            Assert.Throws<ArgumentNullException>(() => builder.WriteBytes(null));
            Assert.Throws<ArgumentNullException>(() => builder.WriteBytes(null, 0, 0));
            Assert.Throws<ArgumentNullException>(() => builder.WriteBytes((byte*)null, 0));
            Assert.Throws<ArgumentNullException>(() => builder.WriteBytes(default(ImmutableArray<byte>)));
            Assert.Throws<ArgumentNullException>(() => builder.WriteBytes(default(ImmutableArray<byte>), 0, 0));

            var bw = default(BlobWriter);
            Assert.Throws<ArgumentNullException>(() => builder.WriteContentTo(ref bw));
            Assert.Throws<ArgumentNullException>(() => builder.WriteContentTo((Stream)null));
            Assert.Throws<ArgumentNullException>(() => builder.WriteContentTo((BlobBuilder)null));

            Assert.Throws<ArgumentOutOfRangeException>(() => builder.TryWriteBytes(new MemoryStream(), -1));
            Assert.Throws<ArgumentOutOfRangeException>(() => builder.WriteBytes(0, -1));
            Assert.Throws<ArgumentOutOfRangeException>(() => builder.WriteBytes(new byte[] { }, 1, 0));
            Assert.Throws<ArgumentOutOfRangeException>(() => builder.WriteBytes(new byte[] { }, 0, 1));
            Assert.Throws<ArgumentOutOfRangeException>(() => builder.WriteBytes(new byte[] { }, 0, -1));
            Assert.Throws<ArgumentOutOfRangeException>(() => builder.WriteBytes(ImmutableArray<byte>.Empty, 1, 0));
            Assert.Throws<ArgumentOutOfRangeException>(() => builder.WriteBytes(ImmutableArray<byte>.Empty, 0, 1));
            Assert.Throws<ArgumentOutOfRangeException>(() => builder.WriteBytes(ImmutableArray<byte>.Empty, 1, -1));
        }
Beispiel #18
0
        public void WriteUTF8_Substring()
        {
            var writer = new BlobBuilder(4);
            writer.WriteUTF8("abc", 0, 0, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new byte[0], writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 0, 1, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new[] { (byte)'a' }, writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 0, 2, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new[] { (byte)'a', (byte)'b' }, writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 0, 3, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new[] { (byte)'a', (byte)'b', (byte)'c' }, writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 1, 0, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new byte[0], writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 1, 1, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new[] { (byte)'b' }, writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 1, 2, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new[] { (byte)'b', (byte)'c' }, writer.ToArray());
            writer.Clear();

            writer.WriteUTF8("abc", 2, 1, allowUnpairedSurrogates: true, prependSize: false);
            AssertEx.Equal(new[] { (byte)'c' }, writer.ToArray());
            writer.Clear();
        }
Beispiel #19
0
        private readonly static byte[] zeroStamp = new byte[4]; // four bytes of zero

        /// <summary>
        /// Write the entire "Debug Directory (Image Only)" along with data that it points to.
        /// </summary>
        internal void WriteDebugTable(BlobBuilder builder, PESectionLocation textSectionLocation, ContentId nativePdbContentId, ContentId portablePdbContentId)
        {
            Debug.Assert(builder.Count == 0);

            int tableSize = ImageDebugDirectoryBaseSize;
            Debug.Assert(tableSize != 0);
            Debug.Assert(nativePdbContentId.IsDefault || portablePdbContentId.IsDefault);
            Debug.Assert(!EmitPdb || (nativePdbContentId.IsDefault ^ portablePdbContentId.IsDefault));

            int dataSize = ComputeSizeOfDebugDirectoryData();
            if (EmitPdb)
            {
                const int IMAGE_DEBUG_TYPE_CODEVIEW = 2; // from PE spec
                uint dataOffset = (uint)(ComputeOffsetToDebugTable() + tableSize);
                WriteDebugTableEntry(builder,
                    stamp: nativePdbContentId.Stamp ?? portablePdbContentId.Stamp,
                    version: portablePdbContentId.IsDefault ? (uint)0 : ('P' << 24 | 'M' << 16 | 0x01 << 8 | 0x00),
                    debugType: IMAGE_DEBUG_TYPE_CODEVIEW,
                    sizeOfData: (uint)dataSize,
                    addressOfRawData: (uint)textSectionLocation.RelativeVirtualAddress + dataOffset, // RVA of the data
                    pointerToRawData: (uint)textSectionLocation.PointerToRawData + dataOffset); // position of the data in the PE stream
            }

            if (IsDeterministic)
            {
                const int IMAGE_DEBUG_TYPE_NO_TIMESTAMP = 16; // from PE spec
                WriteDebugTableEntry(builder,
                    stamp: zeroStamp,
                    version: 0,
                    debugType: IMAGE_DEBUG_TYPE_NO_TIMESTAMP,
                    sizeOfData: 0,
                    addressOfRawData: 0,
                    pointerToRawData: 0);
            }

            // We should now have written all and precisely the data we said we'd write for the table entries.
            Debug.Assert(builder.Count == tableSize);

            // ====================
            // The following is additional data beyond the debug directory at the offset `dataOffset`
            // pointed to by the ImageDebugTypeCodeView entry.

            if (EmitPdb)
            {
                builder.WriteByte((byte)'R');
                builder.WriteByte((byte)'S');
                builder.WriteByte((byte)'D');
                builder.WriteByte((byte)'S');

                // PDB id:
                builder.WriteBytes(nativePdbContentId.Guid ?? portablePdbContentId.Guid);

                // age
                builder.WriteUInt32(1); // TODO: allow specify for native PDBs

                // UTF-8 encoded zero-terminated path to PDB
                int pathStart = builder.Count;
                builder.WriteUTF8(PdbPathOpt, allowUnpairedSurrogates: true);
                builder.WriteByte(0);

                // padding:
                builder.WriteBytes(0, Math.Max(0, MinPdbPath - (builder.Count - pathStart)));
            }

            // We should now have written all and precisely the data we said we'd write for the table and its data.
            Debug.Assert(builder.Count == tableSize + dataSize);
        }
Beispiel #20
0
        internal static void SerializeMetadataHeader(BlobBuilder builder, string metadataVersion, MetadataSizes sizes)
        {
            int startOffset = builder.Count;

            // signature
            builder.WriteUInt32(0x424A5342);

            // major version
            builder.WriteUInt16(1);

            // minor version
            builder.WriteUInt16(1);

            // reserved
            builder.WriteUInt32(0);

            // Spec (section 24.2.1 Metadata Root):
            // Length ... Number of bytes allocated to hold version string (including null terminator), call this x.
            //            Call the length of the string (including the terminator) m (we require m <= 255);
            //            the length x is m rounded up to a multiple of four.
            builder.WriteInt32(sizes.MetadataVersionPaddedLength);

            int metadataVersionStart = builder.Count;

            builder.WriteUTF8(metadataVersion);
            builder.WriteByte(0);
            int metadataVersionEnd = builder.Count;

            for (int i = 0; i < sizes.MetadataVersionPaddedLength - (metadataVersionEnd - metadataVersionStart); i++)
            {
                builder.WriteByte(0);
            }

            // reserved
            builder.WriteUInt16(0);

            // number of streams
            builder.WriteUInt16((ushort)(5 + (sizes.IsEncDelta ? 1 : 0) + (sizes.IsStandaloneDebugMetadata ? 1 : 0)));

            // stream headers
            int offsetFromStartOfMetadata = sizes.MetadataHeaderSize;

            // emit the #Pdb stream first so that only a single page has to be read in order to find out PDB ID
            if (sizes.IsStandaloneDebugMetadata)
            {
                SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.StandalonePdbStreamSize, "#Pdb", builder);
            }

            // Spec: Some compilers store metadata in a #- stream, which holds an uncompressed, or non-optimized, representation of metadata tables;
            // this includes extra metadata -Ptr tables. Such PE files do not form part of ECMA-335 standard.
            //
            // Note: EnC delta is stored as uncompressed metadata stream.
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.MetadataTableStreamSize, (sizes.IsCompressed ? "#~" : "#-"), builder);

            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.String), "#Strings", builder);
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.UserString), "#US", builder);
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID", builder);
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob", builder);

            if (sizes.IsEncDelta)
            {
                SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD", builder);
            }

            int endOffset = builder.Count;

            Debug.Assert(endOffset - startOffset == sizes.MetadataHeaderSize);
        }
Beispiel #21
0
        internal static void SerializeMetadataHeader(BlobBuilder builder, string metadataVersion, MetadataSizes sizes)
        {
            int startOffset = builder.Count;

            // signature
            builder.WriteUInt32(0x424A5342);

            // major version
            builder.WriteUInt16(1);

            // minor version
            builder.WriteUInt16(1);

            // reserved
            builder.WriteUInt32(0);

            // Spec (section 24.2.1 Metadata Root):
            // Length ... Number of bytes allocated to hold version string (including null terminator), call this x.
            //            Call the length of the string (including the terminator) m (we require m <= 255);
            //            the length x is m rounded up to a multiple of four.
            builder.WriteInt32(sizes.MetadataVersionPaddedLength);

            int metadataVersionStart = builder.Count;
            builder.WriteUTF8(metadataVersion);
            builder.WriteByte(0);
            int metadataVersionEnd = builder.Count;

            for (int i = 0; i < sizes.MetadataVersionPaddedLength - (metadataVersionEnd - metadataVersionStart); i++)
            {
                builder.WriteByte(0);
            }

            // reserved
            builder.WriteUInt16(0);

            // number of streams
            builder.WriteUInt16((ushort)(5 + (sizes.IsEncDelta ? 1 : 0) + (sizes.IsStandaloneDebugMetadata ? 1 : 0)));

            // stream headers
            int offsetFromStartOfMetadata = sizes.MetadataHeaderSize;

            // emit the #Pdb stream first so that only a single page has to be read in order to find out PDB ID
            if (sizes.IsStandaloneDebugMetadata)
            {
                SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.StandalonePdbStreamSize, "#Pdb", builder);
            }

            // Spec: Some compilers store metadata in a #- stream, which holds an uncompressed, or non-optimized, representation of metadata tables;
            // this includes extra metadata -Ptr tables. Such PE files do not form part of ECMA-335 standard.
            //
            // Note: EnC delta is stored as uncompressed metadata stream.
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.MetadataTableStreamSize, (sizes.IsCompressed ? "#~" : "#-"), builder);

            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.String), "#Strings", builder);
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.UserString), "#US", builder);
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID", builder);
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob", builder);

            if (sizes.IsEncDelta)
            {
                SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD", builder);
            }

            int endOffset = builder.Count;
            Debug.Assert(endOffset - startOffset == sizes.MetadataHeaderSize);
        }