/// <summary> /// Write a value /// </summary> /// <param name="argType">The ctor arg type, field type, or property type</param> /// <param name="value">The value to write</param> void WriteElem(TypeSig argType, CAArgument value) { if (argType == null) { helper.Error("Custom attribute: Arg type is null"); argType = value.Type; if (argType == null) { return; } } if (!recursionCounter.Increment()) { helper.Error("Infinite recursion"); return; } TypeSig underlyingType; ITypeDefOrRef tdr; switch (argType.ElementType) { case ElementType.Boolean: if (!VerifyTypeAndValue(value, ElementType.Boolean)) { writer.WriteBoolean(ToUInt64(value.Value) != 0); } else { writer.WriteBoolean((bool)value.Value); } break; case ElementType.Char: if (!VerifyTypeAndValue(value, ElementType.Char)) { writer.WriteUInt16((ushort)ToUInt64(value.Value)); } else { writer.WriteUInt16((ushort)(char)value.Value); } break; case ElementType.I1: if (!VerifyTypeAndValue(value, ElementType.I1)) { writer.WriteSByte((sbyte)ToUInt64(value.Value)); } else { writer.WriteSByte((sbyte)value.Value); } break; case ElementType.U1: if (!VerifyTypeAndValue(value, ElementType.U1)) { writer.WriteByte((byte)ToUInt64(value.Value)); } else { writer.WriteByte((byte)value.Value); } break; case ElementType.I2: if (!VerifyTypeAndValue(value, ElementType.I2)) { writer.WriteInt16((short)ToUInt64(value.Value)); } else { writer.WriteInt16((short)value.Value); } break; case ElementType.U2: if (!VerifyTypeAndValue(value, ElementType.U2)) { writer.WriteUInt16((ushort)ToUInt64(value.Value)); } else { writer.WriteUInt16((ushort)value.Value); } break; case ElementType.I4: if (!VerifyTypeAndValue(value, ElementType.I4)) { writer.WriteInt32((int)ToUInt64(value.Value)); } else { writer.WriteInt32((int)value.Value); } break; case ElementType.U4: if (!VerifyTypeAndValue(value, ElementType.U4)) { writer.WriteUInt32((uint)ToUInt64(value.Value)); } else { writer.WriteUInt32((uint)value.Value); } break; case ElementType.I8: if (!VerifyTypeAndValue(value, ElementType.I8)) { writer.WriteInt64((long)ToUInt64(value.Value)); } else { writer.WriteInt64((long)value.Value); } break; case ElementType.U8: if (!VerifyTypeAndValue(value, ElementType.U8)) { writer.WriteUInt64(ToUInt64(value.Value)); } else { writer.WriteUInt64((ulong)value.Value); } break; case ElementType.R4: if (!VerifyTypeAndValue(value, ElementType.R4)) { writer.WriteSingle((float)ToDouble(value.Value)); } else { writer.WriteSingle((float)value.Value); } break; case ElementType.R8: if (!VerifyTypeAndValue(value, ElementType.R8)) { writer.WriteDouble(ToDouble(value.Value)); } else { writer.WriteDouble((double)value.Value); } break; case ElementType.String: if (VerifyTypeAndValue(value, ElementType.String, typeof(UTF8String))) { WriteUTF8String((UTF8String)value.Value); } else if (VerifyTypeAndValue(value, ElementType.String, typeof(string))) { WriteUTF8String((string)value.Value); } else { WriteUTF8String(UTF8String.Empty); } break; case ElementType.ValueType: tdr = ((TypeDefOrRefSig)argType).TypeDefOrRef; underlyingType = GetEnumUnderlyingType(argType); if (underlyingType != null) { WriteElem(underlyingType, value); } else if (tdr is TypeRef && TryWriteEnumUnderlyingTypeValue(value.Value)) { // No error. Assume it's an enum that couldn't be resolved. } else { helper.Error("Custom attribute value is not an enum"); } break; case ElementType.Class: tdr = ((TypeDefOrRefSig)argType).TypeDefOrRef; if (CheckCorLibType(argType, "Type")) { if (CheckCorLibType(value.Type, "Type")) { if (value.Value is TypeSig ts) { WriteType(ts); } else if (value.Value == null) { WriteUTF8String(null); } else { helper.Error("Custom attribute value is not a type"); WriteUTF8String(UTF8String.Empty); } } else { helper.Error("Custom attribute value type is not System.Type"); WriteUTF8String(UTF8String.Empty); } break; } else if (tdr is TypeRef && TryWriteEnumUnderlyingTypeValue(value.Value)) { // No error. Assume it's an enum that couldn't be resolved. break; } goto default; case ElementType.SZArray: WriteValue(argType, value); break; case ElementType.Object: WriteFieldOrPropType(value.Type); WriteElem(value.Type, value); break; case ElementType.End: case ElementType.Void: case ElementType.Ptr: case ElementType.ByRef: case ElementType.Var: case ElementType.Array: case ElementType.GenericInst: case ElementType.TypedByRef: case ElementType.ValueArray: case ElementType.I: case ElementType.U: case ElementType.R: case ElementType.FnPtr: case ElementType.MVar: case ElementType.CModReqd: case ElementType.CModOpt: case ElementType.Internal: case ElementType.Module: case ElementType.Sentinel: case ElementType.Pinned: default: helper.Error("Invalid or unsupported element type in custom attribute"); break; } recursionCounter.Decrement(); }
void Write(TypeSig typeSig) { const ElementType DEFAULT_ELEMENT_TYPE = ElementType.Boolean; if (typeSig == null) { helper.Error("TypeSig is null"); writer.WriteByte((byte)DEFAULT_ELEMENT_TYPE); return; } if (!recursionCounter.Increment()) { helper.Error("Infinite recursion"); writer.WriteByte((byte)DEFAULT_ELEMENT_TYPE); return; } uint count; switch (typeSig.ElementType) { case ElementType.Void: case ElementType.Boolean: case ElementType.Char: case ElementType.I1: case ElementType.U1: case ElementType.I2: case ElementType.U2: case ElementType.I4: case ElementType.U4: case ElementType.I8: case ElementType.U8: case ElementType.R4: case ElementType.R8: case ElementType.String: case ElementType.TypedByRef: case ElementType.I: case ElementType.U: case ElementType.Object: case ElementType.Sentinel: writer.WriteByte((byte)typeSig.ElementType); break; case ElementType.Ptr: case ElementType.ByRef: case ElementType.SZArray: case ElementType.Pinned: writer.WriteByte((byte)typeSig.ElementType); Write(typeSig.Next); break; case ElementType.ValueType: case ElementType.Class: writer.WriteByte((byte)typeSig.ElementType); Write(((TypeDefOrRefSig)typeSig).TypeDefOrRef); break; case ElementType.Var: case ElementType.MVar: writer.WriteByte((byte)typeSig.ElementType); WriteCompressedUInt32(((GenericSig)typeSig).Number); break; case ElementType.Array: writer.WriteByte((byte)typeSig.ElementType); var ary = (ArraySig)typeSig; Write(ary.Next); WriteCompressedUInt32(ary.Rank); if (ary.Rank == 0) { break; } count = WriteCompressedUInt32((uint)ary.Sizes.Count); for (uint i = 0; i < count; i++) { WriteCompressedUInt32(ary.Sizes[(int)i]); } count = WriteCompressedUInt32((uint)ary.LowerBounds.Count); for (uint i = 0; i < count; i++) { WriteCompressedInt32(ary.LowerBounds[(int)i]); } break; case ElementType.GenericInst: writer.WriteByte((byte)typeSig.ElementType); var gis = (GenericInstSig)typeSig; Write(gis.GenericType); count = WriteCompressedUInt32((uint)gis.GenericArguments.Count); for (uint i = 0; i < count; i++) { Write(gis.GenericArguments[(int)i]); } break; case ElementType.ValueArray: writer.WriteByte((byte)typeSig.ElementType); Write(typeSig.Next); WriteCompressedUInt32((typeSig as ValueArraySig).Size); break; case ElementType.FnPtr: writer.WriteByte((byte)typeSig.ElementType); Write((typeSig as FnPtrSig).Signature); break; case ElementType.CModReqd: case ElementType.CModOpt: writer.WriteByte((byte)typeSig.ElementType); Write((typeSig as ModifierSig).Modifier); Write(typeSig.Next); break; case ElementType.Module: writer.WriteByte((byte)typeSig.ElementType); WriteCompressedUInt32((typeSig as ModuleSig).Index); Write(typeSig.Next); break; case ElementType.End: case ElementType.R: case ElementType.Internal: default: helper.Error("Unknown or unsupported element type"); writer.WriteByte((byte)DEFAULT_ELEMENT_TYPE); break; } recursionCounter.Decrement(); }
byte[] Write(MarshalType marshalType) { if (marshalType == null) { return(null); } var type = marshalType.NativeType; if (type != NativeType.RawBlob) { if ((uint)type > byte.MaxValue) { helper.Error("Invalid MarshalType.NativeType"); } writer.WriteByte((byte)type); } bool canWrite = true; switch (type) { case NativeType.FixedSysString: var fixedSysString = (FixedSysStringMarshalType)marshalType; if (fixedSysString.IsSizeValid) { WriteCompressedUInt32((uint)fixedSysString.Size); } break; case NativeType.SafeArray: var safeArray = (SafeArrayMarshalType)marshalType; if (UpdateCanWrite(safeArray.IsVariantTypeValid, "VariantType", ref canWrite)) { WriteCompressedUInt32((uint)safeArray.VariantType); } if (UpdateCanWrite(safeArray.IsUserDefinedSubTypeValid, "UserDefinedSubType", ref canWrite)) { Write(safeArray.UserDefinedSubType.AssemblyQualifiedName); } break; case NativeType.FixedArray: var fixedArray = (FixedArrayMarshalType)marshalType; if (UpdateCanWrite(fixedArray.IsSizeValid, "Size", ref canWrite)) { WriteCompressedUInt32((uint)fixedArray.Size); } if (UpdateCanWrite(fixedArray.IsElementTypeValid, "ElementType", ref canWrite)) { WriteCompressedUInt32((uint)fixedArray.ElementType); } break; case NativeType.Array: var array = (ArrayMarshalType)marshalType; if (UpdateCanWrite(array.IsElementTypeValid, "ElementType", ref canWrite)) { WriteCompressedUInt32((uint)array.ElementType); } if (UpdateCanWrite(array.IsParamNumberValid, "ParamNumber", ref canWrite)) { WriteCompressedUInt32((uint)array.ParamNumber); } if (UpdateCanWrite(array.IsSizeValid, "Size", ref canWrite)) { WriteCompressedUInt32((uint)array.Size); } if (UpdateCanWrite(array.IsFlagsValid, "Flags", ref canWrite)) { WriteCompressedUInt32((uint)array.Flags); } break; case NativeType.CustomMarshaler: var custMarshaler = (CustomMarshalType)marshalType; Write(custMarshaler.Guid); Write(custMarshaler.NativeTypeName); var cm = custMarshaler.CustomMarshaler; var cmName = cm == null ? string.Empty : FullNameFactory.AssemblyQualifiedName(cm, this); Write(cmName); Write(custMarshaler.Cookie); break; case NativeType.IUnknown: case NativeType.IDispatch: case NativeType.IntF: var iface = (InterfaceMarshalType)marshalType; if (iface.IsIidParamIndexValid) { WriteCompressedUInt32((uint)iface.IidParamIndex); } break; case NativeType.RawBlob: var data = ((RawMarshalType)marshalType).Data; if (data != null) { writer.WriteBytes(data); } break; default: break; } return(outStream.ToArray()); }