private void WriteDirectory(Directory directory, BlobBuilder writer, uint offset, uint level, uint sizeOfDirectoryTree, int virtualAddressBase, BlobBuilder dataWriter) { writer.WriteUInt32(0); // Characteristics writer.WriteUInt32(0); // Timestamp writer.WriteUInt32(0); // Version writer.WriteUInt16(directory.NumberOfNamedEntries); writer.WriteUInt16(directory.NumberOfIdEntries); uint n = (uint)directory.Entries.Count; uint k = offset + 16 + n * 8; for (int i = 0; i < n; i++) { int id; string name; uint nameOffset = (uint)dataWriter.Position + sizeOfDirectoryTree; uint directoryOffset = k; Directory subDir = directory.Entries[i] as Directory; if (subDir != null) { id = subDir.ID; name = subDir.Name; if (level == 0) { k += SizeOfDirectory(subDir); } else { k += 16 + 8 * (uint)subDir.Entries.Count; } } else { //EDMAURER write out an IMAGE_RESOURCE_DATA_ENTRY followed //immediately by the data that it refers to. This results //in a layout different than that produced by pulling the resources //from an OBJ. In that case all of the data bits of a resource are //contiguous in .rsrc$02. After processing these will end up at //the end of .rsrc following all of the directory //info and IMAGE_RESOURCE_DATA_ENTRYs IWin32Resource r = (IWin32Resource)directory.Entries[i]; id = level == 0 ? r.TypeId : level == 1 ? r.Id : (int)r.LanguageId; name = level == 0 ? r.TypeName : level == 1 ? r.Name : null; dataWriter.WriteUInt32((uint)(virtualAddressBase + sizeOfDirectoryTree + 16 + dataWriter.Position)); byte[] data = new List<byte>(r.Data).ToArray(); dataWriter.WriteUInt32((uint)data.Length); dataWriter.WriteUInt32(r.CodePage); dataWriter.WriteUInt32(0); dataWriter.WriteBytes(data); while ((dataWriter.Count % 4) != 0) { dataWriter.WriteByte(0); } } if (id >= 0) { writer.WriteInt32(id); } else { if (name == null) { name = string.Empty; } writer.WriteUInt32(nameOffset | 0x80000000); dataWriter.WriteUInt16((ushort)name.Length); dataWriter.WriteUTF16(name); } if (subDir != null) { writer.WriteUInt32(directoryOffset | 0x80000000); } else { writer.WriteUInt32(nameOffset); } } k = offset + 16 + n * 8; for (int i = 0; i < n; i++) { Directory subDir = directory.Entries[i] as Directory; if (subDir != null) { this.WriteDirectory(subDir, writer, k, level + 1, sizeOfDirectoryTree, virtualAddressBase, dataWriter); if (level == 0) { k += SizeOfDirectory(subDir); } else { k += 16 + 8 * (uint)subDir.Entries.Count; } } } }
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)); }
public void WriteUTF16() { var writer = new BlobBuilder(4); writer.WriteUTF16(""); writer.WriteUTF16("a"); writer.WriteUTF16(""); writer.WriteUTF16(new char[0]); writer.WriteUTF16(new char[] { '\ud800' }); // hi surrogate writer.WriteUTF16("\udc00"); // lo surrogate writer.WriteUTF16("\ud800\udc00"); // pair writer.WriteUTF16(new char[] { '\udc00', '\ud800' }); // lo + hi writer.WriteUTF16("\u1234"); AssertEx.Equal(new byte[] { 0x61, 0x00, 0x00, 0xD8, 0x00, 0xDC, 0x00, 0xD8, 0x00, 0xDC, 0x00, 0xDC, 0x00, 0xD8, 0x34, 0x12 }, writer.ToArray()); }
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()); }
private BlobHandle SerializeLocalConstantSignature(ILocalDefinition localConstant) { var builder = new BlobBuilder(); // TODO: BlobEncoder.LocalConstantSignature // CustomMod* var encoder = new CustomModifiersEncoder(builder); SerializeCustomModifiers(encoder, localConstant.CustomModifiers); var type = localConstant.Type; var typeCode = type.TypeCode; object value = localConstant.CompileTimeValue.Value; // PrimitiveConstant or EnumConstant if (value is decimal) { builder.WriteByte((byte)SignatureTypeKind.ValueType); builder.WriteCompressedInteger(CodedIndex.TypeDefOrRefOrSpec(GetTypeHandle(type))); builder.WriteDecimal((decimal)value); } else if (value is DateTime) { builder.WriteByte((byte)SignatureTypeKind.ValueType); builder.WriteCompressedInteger(CodedIndex.TypeDefOrRefOrSpec(GetTypeHandle(type))); builder.WriteDateTime((DateTime)value); } else if (typeCode == PrimitiveTypeCode.String) { builder.WriteByte((byte)ConstantTypeCode.String); if (value == null) { builder.WriteByte(0xff); } else { builder.WriteUTF16((string)value); } } else if (value != null) { // TypeCode builder.WriteByte((byte)GetConstantTypeCode(value)); // Value builder.WriteConstant(value); // EnumType if (type.IsEnum) { builder.WriteCompressedInteger(CodedIndex.TypeDefOrRefOrSpec(GetTypeHandle(type))); } } else if (this.module.IsPlatformType(type, PlatformType.SystemObject)) { builder.WriteByte((byte)SignatureTypeCode.Object); } else { builder.WriteByte((byte)(type.IsValueType ? SignatureTypeKind.ValueType : SignatureTypeKind.Class)); builder.WriteCompressedInteger(CodedIndex.TypeDefOrRefOrSpec(GetTypeHandle(type))); } return(_debugMetadataOpt.GetOrAddBlob(builder)); }
internal static void WriteConstant(BlobBuilder writer, object value) { if (value == null) { // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 32-bit. writer.WriteUInt32(0); return; } var type = value.GetType(); if (type.GetTypeInfo().IsEnum) { type = Enum.GetUnderlyingType(type); } if (type == typeof(bool)) { writer.WriteBoolean((bool)value); } else if (type == typeof(int)) { writer.WriteInt32((int)value); } else if (type == typeof(string)) { writer.WriteUTF16((string)value); } else if (type == typeof(byte)) { writer.WriteByte((byte)value); } else if (type == typeof(char)) { writer.WriteUInt16((char)value); } else if (type == typeof(double)) { writer.WriteDouble((double)value); } else if (type == typeof(short)) { writer.WriteInt16((short)value); } else if (type == typeof(long)) { writer.WriteInt64((long)value); } else if (type == typeof(sbyte)) { writer.WriteSByte((sbyte)value); } else if (type == typeof(float)) { writer.WriteSingle((float)value); } else if (type == typeof(ushort)) { writer.WriteUInt16((ushort)value); } else if (type == typeof(uint)) { writer.WriteUInt32((uint)value); } else if (type == typeof(ulong)) { writer.WriteUInt64((ulong)value); } else { // TODO: message throw new ArgumentException(); } }
/// <exception cref="ImageFormatLimitationException">The remaining space on the heap is too small to fit the string.</exception> public UserStringHandle GetOrAddUserString(string str) { int index; if (!_userStrings.TryGetValue(str, out index)) { Debug.Assert(!_streamsAreComplete); int startPosition = _userStringWriter.Position; int encodedLength = str.Length * 2 + 1; index = startPosition + _userStringHeapStartOffset; // Native metadata emitter allows strings to exceed the heap size limit as long // as the index is within the limits (see https://github.com/dotnet/roslyn/issues/9852) if (index > UserStringHeapSizeLimit) { ImageFormatLimitationException.ThrowHeapSizeLimitExceeded(HeapIndex.UserString); } _userStrings.Add(str, index); _userStringWriter.WriteCompressedInteger(encodedLength); _userStringWriter.WriteUTF16(str); // Write out a trailing byte indicating if the string is really quite simple byte stringKind = 0; foreach (char ch in str) { if (ch >= 0x7F) { stringKind = 1; } else { switch ((int)ch) { case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: case 0x8: case 0xE: case 0xF: case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: case 0x27: case 0x2D: stringKind = 1; break; default: continue; } } break; } _userStringWriter.WriteByte(stringKind); } return(MetadataTokens.UserStringHandle(index)); }
public int GetUserStringToken(string str) { int index; if (!_userStrings.TryGetValue(str, out index)) { Debug.Assert(!_streamsAreComplete); index = _userStringWriter.Position + _userStringHeapStartOffset; _userStrings.Add(str, index); _userStringWriter.WriteCompressedInteger((uint)str.Length * 2 + 1); _userStringWriter.WriteUTF16(str); // Write out a trailing byte indicating if the string is really quite simple byte stringKind = 0; foreach (char ch in str) { if (ch >= 0x7F) { stringKind = 1; } else { switch ((int)ch) { case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: case 0x8: case 0xE: case 0xF: case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: case 0x27: case 0x2D: stringKind = 1; break; default: continue; } } break; } _userStringWriter.WriteByte(stringKind); } return(0x70000000 | index); }