// dnlib: See LICENSE.txt for more info using System; using System.IO; namespace dnlib.DotNet.Writer { /// /// Writes field marshal blobs /// public readonly struct MarshalBlobWriter : IDisposable, IFullNameFactoryHelper { readonly ModuleDef module; readonly MemoryStream outStream; readonly DataWriter writer; readonly IWriterError helper; readonly bool optimizeCustomAttributeSerializedTypeNames; /// /// Creates a field marshal blob from /// /// Owner module /// Marshal type /// Helps this class /// A field marshal blob or null if is /// null public static byte[] Write(ModuleDef module, MarshalType marshalType, IWriterError helper) => Write(module, marshalType, helper, false); /// /// Creates a field marshal blob from /// /// Owner module /// Marshal type /// Helps this class /// Optimize serialized type strings in custom attributes. /// For more info, see /// A field marshal blob or null if is /// null public static byte[] Write(ModuleDef module, MarshalType marshalType, IWriterError helper, bool optimizeCustomAttributeSerializedTypeNames) { using (var writer = new MarshalBlobWriter(module, helper, optimizeCustomAttributeSerializedTypeNames)) return writer.Write(marshalType); } MarshalBlobWriter(ModuleDef module, IWriterError helper, bool optimizeCustomAttributeSerializedTypeNames) { this.module = module; outStream = new MemoryStream(); writer = new DataWriter(outStream); this.helper = helper; this.optimizeCustomAttributeSerializedTypeNames = optimizeCustomAttributeSerializedTypeNames; } byte[] Write(MarshalType marshalType) { if (marshalType is 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 is 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 is not null) writer.WriteBytes(data); break; default: break; } return outStream.ToArray(); } bool UpdateCanWrite(bool isValid, string field, ref bool canWriteMore) { if (!canWriteMore) { if (isValid) helper.Error2("MarshalType field {0} is valid even though a previous field was invalid.", field); return canWriteMore; } if (!isValid) canWriteMore = false; return canWriteMore; } uint WriteCompressedUInt32(uint value) => writer.WriteCompressedUInt32(helper, value); void Write(UTF8String s) => writer.Write(helper, s); /// public void Dispose() => outStream?.Dispose(); bool IFullNameFactoryHelper.MustUseAssemblyName(IType type) => FullNameFactory.MustUseAssemblyName(module, type, optimizeCustomAttributeSerializedTypeNames); } }