152 lines
5.4 KiB
C#
152 lines
5.4 KiB
C#
// dnlib: See LICENSE.txt for more info
|
|
|
|
using System;
|
|
using System.IO;
|
|
|
|
namespace dnlib.DotNet.Writer {
|
|
/// <summary>
|
|
/// Writes field marshal blobs
|
|
/// </summary>
|
|
public readonly struct MarshalBlobWriter : IDisposable, IFullNameFactoryHelper {
|
|
readonly ModuleDef module;
|
|
readonly MemoryStream outStream;
|
|
readonly DataWriter writer;
|
|
readonly IWriterError helper;
|
|
readonly bool optimizeCustomAttributeSerializedTypeNames;
|
|
|
|
/// <summary>
|
|
/// Creates a field marshal blob from <paramref name="marshalType"/>
|
|
/// </summary>
|
|
/// <param name="module">Owner module</param>
|
|
/// <param name="marshalType">Marshal type</param>
|
|
/// <param name="helper">Helps this class</param>
|
|
/// <returns>A field marshal blob or <c>null</c> if <paramref name="marshalType"/> is
|
|
/// <c>null</c></returns>
|
|
public static byte[] Write(ModuleDef module, MarshalType marshalType, IWriterError helper) =>
|
|
Write(module, marshalType, helper, false);
|
|
|
|
/// <summary>
|
|
/// Creates a field marshal blob from <paramref name="marshalType"/>
|
|
/// </summary>
|
|
/// <param name="module">Owner module</param>
|
|
/// <param name="marshalType">Marshal type</param>
|
|
/// <param name="helper">Helps this class</param>
|
|
/// <param name="optimizeCustomAttributeSerializedTypeNames">Optimize serialized type strings in custom attributes.
|
|
/// For more info, see <see cref="MetadataFlags.OptimizeCustomAttributeSerializedTypeNames"/></param>
|
|
/// <returns>A field marshal blob or <c>null</c> if <paramref name="marshalType"/> is
|
|
/// <c>null</c></returns>
|
|
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);
|
|
|
|
/// <inheritdoc/>
|
|
public void Dispose() => outStream?.Dispose();
|
|
|
|
bool IFullNameFactoryHelper.MustUseAssemblyName(IType type) =>
|
|
FullNameFactory.MustUseAssemblyName(module, type, optimizeCustomAttributeSerializedTypeNames);
|
|
}
|
|
}
|