/// <summary> /// Reads a raw <c>GenericParam</c> row or returns false if the row doesn't exist /// </summary> /// <param name="rid">Row ID</param> /// <param name="row">Row data</param> /// <returns></returns> public bool TryReadGenericParamRow(uint rid, out RawGenericParamRow row) { var table = GenericParamTable; if (table.IsInvalidRID(rid)) { row = default; return(false); } var reader = table.DataReader; reader.Position = (rid - 1) * (uint)table.TableInfo.RowSize; if (table.Column4 == null) { row = new RawGenericParamRow( reader.Unsafe_ReadUInt16(), reader.Unsafe_ReadUInt16(), table.Column2.Unsafe_Read24(ref reader), table.Column3.Unsafe_Read24(ref reader)); return(true); } else { row = new RawGenericParamRow( reader.Unsafe_ReadUInt16(), reader.Unsafe_ReadUInt16(), table.Column2.Unsafe_Read24(ref reader), table.Column3.Unsafe_Read24(ref reader), table.Column4.Unsafe_Read24(ref reader)); return(true); } }
public int GetHashCode(RawGenericParamRow obj) { return((int)obj.Number + rol(obj.Flags, 3) + rol(obj.Owner, 7) + rol(obj.Name, 11) + rol(obj.Kind, 15)); }
public bool Equals(RawGenericParamRow x, RawGenericParamRow y) { return(x.Number == y.Number && x.Flags == y.Flags && x.Owner == y.Owner && x.Name == y.Name && x.Kind == y.Kind); }
void InitializeRawRow() { if (rawRow != null) { return; } rawRow = readerModule.TablesStream.ReadGenericParamRow(rid); }
/// <summary> /// Patches all columns and blob signatures that reference a moved TypeDef so they reference the new TypeRef /// </summary> void PatchTypeTokenReferences(TypeDef nonNestedEditedType) { if (remappedTypeTokens.Count == 0) { return; } // NOTE: We don't patch the following: // - Method bodies // - All MemberRefs referenced by method bodies // - StandAloneSig.Signature. It's only used by method bodies // - MethodSpec.Instantiation. It's only used by method bodies // - Custom attribute blobs. Could reference the edited type but not likely to cause a problem. // - Marshal blobs. Could reference the edited type but not likely to cause a problem. // The MD writer doesn't write the FieldMarshal table. var tablesHeap = mdEditor.TablesHeap; var typeSigDict = new Dictionary <uint, uint>(); var callConvSigDict = new Dictionary <uint, uint>(); MDTable table; byte * p; int rowSize; ColumnInfo column, column2; uint i, codedToken, newToken, sig, newSig, rid; MDToken token; // Patch the TypeDef table { table = mdEditor.RealMetadata.TablesStream.TypeDefTable; p = peFile + (int)table.StartOffset; rowSize = (int)table.RowSize; column = table.Columns[3]; p += column.Offset; for (i = 0; i < table.Rows; i++, p += rowSize) { codedToken = column.Size == 2 ? *(ushort *)p : *(uint *)p; if (!CodedToken.TypeDefOrRef.Decode(codedToken, out token)) { continue; } if (remappedTypeTokens.TryGetValue(token.Raw, out newToken)) { var row = tablesHeap.TypeDefTable.Get(i + 1); row = new RawTypeDefRow(row.Flags, row.Name, row.Namespace, CodedToken.TypeDefOrRef.Encode(newToken), row.FieldList, row.MethodList); tablesHeap.TypeDefTable.Set(i + 1, ref row); } } } // Patch the Field table { table = mdEditor.RealMetadata.TablesStream.FieldTable; p = peFile + (int)table.StartOffset; rowSize = (int)table.RowSize; column = table.Columns[2]; p += column.Offset; for (i = 0; i < table.Rows; i++, p += rowSize) { sig = column.Size == 2 ? *(ushort *)p : *(uint *)p; newSig = PatchCallingConventionSignature(callConvSigDict, sig); if (newSig != sig) { var row = tablesHeap.FieldTable.Get(i + 1); row = new RawFieldRow(row.Flags, row.Name, newSig); tablesHeap.FieldTable.Set(i + 1, ref row); } } } // Patch the Method table { table = mdEditor.RealMetadata.TablesStream.MethodTable; p = peFile + (int)table.StartOffset; rowSize = (int)table.RowSize; column = table.Columns[4]; p += column.Offset; for (i = 0; i < table.Rows; i++, p += rowSize) { sig = column.Size == 2 ? *(ushort *)p : *(uint *)p; newSig = PatchCallingConventionSignature(callConvSigDict, sig); if (newSig != sig) { var row = tablesHeap.MethodTable.Get(i + 1); row = new RawMethodRow(row.RVA, row.ImplFlags, row.Flags, row.Name, newSig, row.ParamList); tablesHeap.MethodTable.Set(i + 1, ref row); } } } // Patch the InterfaceImpl table { table = mdEditor.RealMetadata.TablesStream.InterfaceImplTable; p = peFile + (int)table.StartOffset; rowSize = (int)table.RowSize; column = table.Columns[1]; p += column.Offset; for (i = 0; i < table.Rows; i++, p += rowSize) { codedToken = column.Size == 2 ? *(ushort *)p : *(uint *)p; if (!CodedToken.TypeDefOrRef.Decode(codedToken, out token)) { continue; } if (remappedTypeTokens.TryGetValue(token.Raw, out newToken)) { var row = tablesHeap.InterfaceImplTable.Get(i + 1); row = new RawInterfaceImplRow(row.Class, CodedToken.TypeDefOrRef.Encode(newToken)); tablesHeap.InterfaceImplTable.Set(i + 1, ref row); } } } //TODO: PERF: If needed, this table could mostly be skipped. We only need to update refs from: // CustomAttribute.Type, MethodImpl.MethodBody, MethodImpl.MethodDeclaration // CustomAttribute.Type almost never references the edited type, and if it does, the // edited type, or any of its nested types, is an attribute. Quick test: this block // took ~25% of the total time (patch file, write new MD, test file was dnSpy.exe = 3.3MB). // Patch the MemberRef table { table = mdEditor.RealMetadata.TablesStream.MemberRefTable; p = peFile + (int)table.StartOffset; rowSize = (int)table.RowSize; column = table.Columns[0]; column2 = table.Columns[2]; for (i = 0; i < table.Rows; i++, p += rowSize) { codedToken = column.Size == 2 ? *(ushort *)p : *(uint *)p; if (!CodedToken.MemberRefParent.Decode(codedToken, out token)) { continue; } rid = i + 1; RawMemberRefRow row; switch (token.Table) { case Table.TypeRef: case Table.TypeDef: case Table.TypeSpec: if (remappedTypeTokens.TryGetValue(token.Raw, out newToken)) { row = tablesHeap.MemberRefTable.Get(rid); row = new RawMemberRefRow(CodedToken.MemberRefParent.Encode(newToken), row.Name, row.Signature); tablesHeap.MemberRefTable.Set(rid, ref row); } break; case Table.ModuleRef: if (nonNestedEditedType.IsGlobalModuleType && CheckResolutionScopeIsSameModule(token, nonNestedEditedType.Module)) { if (remappedTypeTokens.TryGetValue(nonNestedEditedType.MDToken.Raw, out newToken)) { row = tablesHeap.MemberRefTable.Get(rid); row = new RawMemberRefRow(CodedToken.MemberRefParent.Encode(newToken), row.Name, row.Signature); tablesHeap.MemberRefTable.Set(rid, ref row); } } break; case Table.Method: break; default: Debug.Fail("Impossible"); break; } sig = column2.Size == 2 ? *(ushort *)(p + column2.Offset) : *(uint *)(p + column2.Offset); newSig = PatchCallingConventionSignature(callConvSigDict, sig); if (sig != newSig) { row = tablesHeap.MemberRefTable.Get(rid); row = new RawMemberRefRow(row.Class, row.Name, newSig); tablesHeap.MemberRefTable.Set(rid, ref row); } } } // Patch the Event table { table = mdEditor.RealMetadata.TablesStream.EventTable; p = peFile + (int)table.StartOffset; rowSize = (int)table.RowSize; column = table.Columns[2]; p += column.Offset; for (i = 0; i < table.Rows; i++, p += rowSize) { codedToken = column.Size == 2 ? *(ushort *)p : *(uint *)p; if (!CodedToken.TypeDefOrRef.Decode(codedToken, out token)) { continue; } if (remappedTypeTokens.TryGetValue(token.Raw, out newToken)) { var row = tablesHeap.EventTable.Get(i + 1); row = new RawEventRow(row.EventFlags, row.Name, CodedToken.TypeDefOrRef.Encode(newToken)); tablesHeap.EventTable.Set(i + 1, ref row); } } } // Patch the Property table { table = mdEditor.RealMetadata.TablesStream.PropertyTable; p = peFile + (int)table.StartOffset; rowSize = (int)table.RowSize; column = table.Columns[2]; p += column.Offset; for (i = 0; i < table.Rows; i++, p += rowSize) { sig = column.Size == 2 ? *(ushort *)p : *(uint *)p; newSig = PatchCallingConventionSignature(callConvSigDict, sig); if (newSig != sig) { var row = tablesHeap.PropertyTable.Get(i + 1); row = new RawPropertyRow(row.PropFlags, row.Name, newSig); tablesHeap.PropertyTable.Set(i + 1, ref row); } } } // Patch the TypeSpec table { table = mdEditor.RealMetadata.TablesStream.TypeSpecTable; p = peFile + (int)table.StartOffset; rowSize = (int)table.RowSize; column = table.Columns[0]; for (i = 0; i < table.Rows; i++, p += rowSize) { sig = column.Size == 2 ? *(ushort *)p : *(uint *)p; newSig = PatchTypeSignature(typeSigDict, sig); if (newSig != sig) { var row = new RawTypeSpecRow(newSig); tablesHeap.TypeSpecTable.Set(i + 1, ref row); } } } // Patch the GenericParam table if (mdEditor.RealMetadata.TablesStream.GenericParamTable.Columns.Count == 5) { table = mdEditor.RealMetadata.TablesStream.GenericParamTable; p = peFile + (int)table.StartOffset; rowSize = (int)table.RowSize; column = table.Columns[4]; p += column.Offset; for (i = 0; i < table.Rows; i++, p += rowSize) { codedToken = column.Size == 2 ? *(ushort *)p : *(uint *)p; if (!CodedToken.TypeDefOrRef.Decode(codedToken, out token)) { continue; } if (remappedTypeTokens.TryGetValue(token.Raw, out newToken)) { var row = tablesHeap.GenericParamTable.Get(i + 1); row = new RawGenericParamRow(row.Number, row.Flags, row.Owner, row.Name, CodedToken.TypeDefOrRef.Encode(newToken)); tablesHeap.GenericParamTable.Set(i + 1, ref row); } } } // Patch the GenericParamConstraint table { table = mdEditor.RealMetadata.TablesStream.GenericParamConstraintTable; p = peFile + (int)table.StartOffset; rowSize = (int)table.RowSize; column = table.Columns[1]; p += column.Offset; for (i = 0; i < table.Rows; i++, p += rowSize) { codedToken = column.Size == 2 ? *(ushort *)p : *(uint *)p; if (!CodedToken.TypeDefOrRef.Decode(codedToken, out token)) { continue; } if (remappedTypeTokens.TryGetValue(token.Raw, out newToken)) { var row = tablesHeap.GenericParamConstraintTable.Get(i + 1); row = new RawGenericParamConstraintRow(row.Owner, CodedToken.TypeDefOrRef.Encode(newToken)); tablesHeap.GenericParamConstraintTable.Set(i + 1, ref row); } } } }
static uint ReadGenericParamColumnMethod(ref RawGenericParamRow row, int index) => row[index];