private static object ReadValue(ModuleDefinition parentModule, TypeSignature valueType, IBinaryStreamReader reader) { switch (valueType.ElementType) { case ElementType.Boolean: return(reader.ReadByte() == 1); case ElementType.Char: return((char)reader.ReadUInt16()); case ElementType.R4: return(reader.ReadSingle()); case ElementType.R8: return(reader.ReadDouble()); case ElementType.I1: return(reader.ReadSByte()); case ElementType.I2: return(reader.ReadInt16()); case ElementType.I4: return(reader.ReadInt32()); case ElementType.I8: return(reader.ReadInt64()); case ElementType.U1: return(reader.ReadByte()); case ElementType.U2: return(reader.ReadUInt16()); case ElementType.U4: return(reader.ReadUInt32()); case ElementType.U8: return(reader.ReadUInt64()); case ElementType.String: return(reader.ReadSerString()); case ElementType.Object: return(ReadValue(parentModule, TypeSignature.ReadFieldOrPropType(parentModule, reader), reader)); case ElementType.Class: case ElementType.Enum: case ElementType.ValueType: var enumTypeDef = parentModule.MetadataResolver.ResolveType(valueType); if (enumTypeDef != null && enumTypeDef.IsEnum) { return(ReadValue(parentModule, enumTypeDef.GetEnumUnderlyingType(), reader)); } break; } if (valueType.IsTypeOf("System", "Type")) { return(TypeNameParser.Parse(parentModule, reader.ReadSerString())); } throw new NotSupportedException($"Unsupported element type {valueType.ElementType}."); }
private void WriteElement(TypeSignature argumentType, object element) { var writer = _context.Writer; if (argumentType.IsTypeOf("System", "Type")) { writer.WriteSerString(TypeNameBuilder.GetAssemblyQualifiedName((TypeSignature)element)); return; } switch (argumentType.ElementType) { case ElementType.Boolean: writer.WriteByte((byte)((bool)element ? 1 : 0)); break; case ElementType.Char: writer.WriteUInt16((char)element); break; case ElementType.I1: writer.WriteSByte((sbyte)element); break; case ElementType.U1: writer.WriteByte((byte)element); break; case ElementType.I2: writer.WriteInt16((short)element); break; case ElementType.U2: writer.WriteUInt16((ushort)element); break; case ElementType.I4: writer.WriteInt32((int)element); break; case ElementType.U4: writer.WriteUInt32((uint)element); break; case ElementType.I8: writer.WriteInt64((long)element); break; case ElementType.U8: writer.WriteUInt64((ulong)element); break; case ElementType.R4: writer.WriteSingle((float)element); break; case ElementType.R8: writer.WriteDouble((double)element); break; case ElementType.String: writer.WriteSerString(element as string); break; case ElementType.Object: TypeSignature innerTypeSig; object value; if (element is null) { // Most efficient way to store "null" is writing null as a string (two bytes). innerTypeSig = argumentType.Module.CorLibTypeFactory.String; value = null; } else if (element is BoxedArgument boxedArgument) { // Write the boxed argument. innerTypeSig = boxedArgument.Type; value = boxedArgument.Value; } else { _context.DiagnosticBag.RegisterException(new NotSupportedException( $"Object elements in a custom attribute signature should be either 'null' or an instance of {nameof(BoxedArgument)}.")); // Write null as a recovery. innerTypeSig = argumentType.Module.CorLibTypeFactory.String; value = null; } TypeSignature.WriteFieldOrPropType(writer, innerTypeSig); WriteElement(innerTypeSig, value); break; case ElementType.SzArray: WriteArrayElement( (SzArrayTypeSignature)argumentType, element as IList <object> ?? new object[0], element == null); break; case ElementType.Class: case ElementType.Enum: case ElementType.ValueType: WriteEnumValue(argumentType, element); break; default: UnsupportedArgumentType(argumentType); break; } }
private void WriteValue(IBinaryStreamWriter writer, TypeSignature argumentType, ITypeCodedIndexProvider provider, object value) { if (argumentType.IsTypeOf("System", "Type")) { writer.WriteSerString(TypeNameBuilder.GetAssemblyQualifiedName((TypeSignature)value)); return; } switch (argumentType.ElementType) { case ElementType.Boolean: writer.WriteByte((byte)((bool)value ? 1 : 0)); break; case ElementType.Char: writer.WriteUInt16((char)value); break; case ElementType.I1: writer.WriteSByte((sbyte)value); break; case ElementType.U1: writer.WriteByte((byte)value); break; case ElementType.I2: writer.WriteInt16((short)value); break; case ElementType.U2: writer.WriteUInt16((ushort)value); break; case ElementType.I4: writer.WriteInt32((int)value); break; case ElementType.U4: writer.WriteUInt32((uint)value); break; case ElementType.I8: writer.WriteInt64((long)value); break; case ElementType.U8: writer.WriteUInt64((ulong)value); break; case ElementType.R4: writer.WriteSingle((float)value); break; case ElementType.R8: writer.WriteDouble((double)value); break; case ElementType.String: writer.WriteSerString(value as string); break; case ElementType.Object: var valueType = value.GetType(); var innerTypeSig = argumentType.Module.CorLibTypeFactory.FromName(valueType.Namespace, valueType.Name); TypeSignature.WriteFieldOrPropType(writer, innerTypeSig); WriteValue(writer, innerTypeSig, provider, value); break; case ElementType.Class: case ElementType.Enum: case ElementType.ValueType: var enumTypeDef = argumentType.Resolve(); if (enumTypeDef != null && enumTypeDef.IsEnum) { WriteValue(writer, enumTypeDef.GetEnumUnderlyingType(), provider, Value); } else { throw new NotImplementedException(); } break; default: throw new ArgumentOutOfRangeException(); } }
public void ReadValue(TypeSignature valueType) { if (valueType.IsTypeOf("System", "Type")) { Elements.Add(TypeNameParser.Parse(_parentModule, _reader.ReadSerString())); return; } switch (valueType.ElementType) { case ElementType.Boolean: Elements.Add(_reader.ReadByte() == 1); break; case ElementType.Char: Elements.Add((char)_reader.ReadUInt16()); break; case ElementType.R4: Elements.Add(_reader.ReadSingle()); break; case ElementType.R8: Elements.Add(_reader.ReadDouble()); break; case ElementType.I1: Elements.Add(_reader.ReadSByte()); break; case ElementType.I2: Elements.Add(_reader.ReadInt16()); break; case ElementType.I4: Elements.Add(_reader.ReadInt32()); break; case ElementType.I8: Elements.Add(_reader.ReadInt64()); break; case ElementType.U1: Elements.Add(_reader.ReadByte()); break; case ElementType.U2: Elements.Add(_reader.ReadUInt16()); break; case ElementType.U4: Elements.Add(_reader.ReadUInt32()); break; case ElementType.U8: Elements.Add(_reader.ReadUInt64()); break; case ElementType.String: Elements.Add(_reader.ReadSerString()); break; case ElementType.Object: var reader = new CustomAttributeArgumentReader(_parentModule, _reader); var type = TypeSignature.ReadFieldOrPropType(_parentModule, _reader); reader.ReadValue(type); Elements.Add(new BoxedArgument(type, type.ElementType == ElementType.SzArray ? reader.Elements.ToArray() : reader.Elements[0])); break; case ElementType.SzArray: var arrayElementType = ((SzArrayTypeSignature)valueType).BaseType; uint elementCount = _reader.CanRead(sizeof(uint)) ? _reader.ReadUInt32() : uint.MaxValue; IsNullArray = elementCount == uint.MaxValue; if (!IsNullArray) { for (uint i = 0; i < elementCount; i++) { ReadValue(arrayElementType); } } break; case ElementType.Class: case ElementType.Enum: case ElementType.ValueType: // Value is an enum, resolve it and get underlying type. // If that fails, most enums are int32s, assume that is the case in an attempt to recover. var enumTypeDef = _parentModule.MetadataResolver.ResolveType(valueType); TypeSignature underlyingType; if (enumTypeDef is null) { underlyingType = _parentModule.CorLibTypeFactory.Int32; } else if (enumTypeDef.IsEnum) { underlyingType = enumTypeDef.GetEnumUnderlyingType() ?? _parentModule.CorLibTypeFactory.Int32; } else { throw new NotSupportedException($"Type {valueType} is not an enum."); } ReadValue(underlyingType); break; default: throw new NotSupportedException($"Unsupported element type {valueType.ElementType}."); } }