internal void GetSystemTableRows(out ulong mask, uint[] tables) { if (tables.Length != 0x40) { throw new InvalidOperationException(); } var tablesMask = GetValidMask(); ulong bit = 1; mask = 0; for (int i = 0; i < 0x40; i++, bit <<= 1) { var table = (Table)i; if (DotNetTableSizes.IsSystemTable(table)) { if ((tablesMask & bit) != 0) { tables[i] = (uint)Tables[i].Rows; mask |= bit; } else { tables[i] = 0; } } else { tables[i] = 0; } } }
/// <summary> /// Calculates the length. This will set all MD tables to read-only. /// </summary> public void CalculateLength() { if (length != 0) { return; } SetReadOnly(); majorVersion = options.MajorVersion ?? 2; minorVersion = options.MinorVersion ?? 0; if (((majorVersion << 8) | minorVersion) <= 0x100) { if (!GenericParamTable.IsEmpty || !MethodSpecTable.IsEmpty || !GenericParamConstraintTable.IsEmpty) { throw new ModuleWriterException("Tables heap version <= v1.0 but generic tables are not empty"); } } var dnTableSizes = new DotNetTableSizes(); var tableInfos = dnTableSizes.CreateTables(majorVersion, minorVersion); var rowCounts = GetRowCounts(); dnTableSizes.InitializeSizes(bigStrings, bigGuid, bigBlob, systemTables ?? rowCounts, rowCounts); for (int i = 0; i < Tables.Length; i++) { Tables[i].TableInfo = tableInfos[i]; } length = 24; foreach (var mdt in Tables) { if (mdt.IsEmpty) { continue; } length += (uint)(4 + mdt.TableInfo.RowSize * mdt.Rows); } if (options.ExtraData.HasValue) { length += 4; } }
public unsafe override void Write(MDWriter mdWriter, MDWriterStream stream, byte[] tempBuffer) { var tblStream = mdWriter.MetadataEditor.RealMetadata.TablesStream; stream.Write(tblStream.Reserved1); stream.Write((byte)(tblStream.Version >> 8)); stream.Write((byte)tblStream.Version); stream.Write((byte)mdStreamFlags); stream.Write((byte)1); stream.Write(GetValidMask(tablesHeap)); stream.Write(GetSortedMask(tablesHeap, tblStream.SortedMask)); var rowCounts = new uint[tablesHeap.TableInfos.Length]; var infos = tablesHeap.TableInfos; for (int i = 0; i < infos.Length; i++) { if (tablesToIgnore[i]) { continue; } var info = infos[i]; if (info != null && !info.IsEmpty) { rowCounts[i] = info.Rows; stream.Write(info.Rows); } } var dnTableSizes = new DotNetTableSizes(); var tableInfos = dnTableSizes.CreateTables((byte)(tblStream.Version >> 8), (byte)tblStream.Version); dnTableSizes.InitializeSizes((mdStreamFlags & MDStreamFlags.BigStrings) != 0, (mdStreamFlags & MDStreamFlags.BigGUID) != 0, (mdStreamFlags & MDStreamFlags.BigBlob) != 0, rowCounts, rowCounts); long totalSize = 0; for (int i = 0; i < infos.Length; i++) { if (tablesToIgnore[i]) { continue; } var info = infos[i]; if (info != null && !info.IsEmpty) { totalSize += (long)info.Rows * tableInfos[i].RowSize; } } // NOTE: We don't write method bodies or field data, the compiler shouldn't // read Method.RVA. We also don't write the FieldRVA table. // PERF: Write to a temp buffer followed by a call to stream.Write(byte[]). It's faster // than calling stream.Write() for every row + column. var tablesPos = stream.Position; int tempBufferIndex = 0; for (int i = 0; i < infos.Length; i++) { if (tablesToIgnore[i]) { continue; } var info = infos[i]; if (info == null || info.IsEmpty) { continue; } var tableWriter = TableWriter.Create(info); var mdTable = info.MDTable; var tbl = tableInfos[i]; var columns = tbl.Columns; var rows = tableWriter.Rows; uint currentRowIndex = 0; var rowSize = (uint)tbl.RowSize; Debug.Assert(tempBuffer.Length >= rowSize, "Temp buffer is too small"); // If there are no changes in the original metadata or layout, just copy everything uint unmodifiedRows = tableWriter.FirstModifiedRowId - 1; if (unmodifiedRows > 0 && Equals(mdTable.TableInfo, tbl)) { if (tempBufferIndex > 0) { stream.Write(tempBuffer, 0, tempBufferIndex); tempBufferIndex = 0; } stream.Write((byte *)mdWriter.ModuleData.Pointer + (int)mdTable.StartOffset, (int)(unmodifiedRows * mdTable.RowSize)); Debug.Assert(unmodifiedRows <= rows); rows -= unmodifiedRows; currentRowIndex += unmodifiedRows; } while (rows > 0) { int bytesLeft = tempBuffer.Length - tempBufferIndex; uint maxRows = Math.Min((uint)bytesLeft / rowSize, rows); if (maxRows == 0) { stream.Write(tempBuffer, 0, tempBufferIndex); tempBufferIndex = 0; bytesLeft = tempBuffer.Length; maxRows = Math.Min((uint)bytesLeft / rowSize, rows); } Debug.Assert(maxRows > 0); for (uint endRowIndex = currentRowIndex + maxRows; currentRowIndex < endRowIndex; currentRowIndex++, tempBufferIndex += (int)rowSize) { tableWriter.WriteRow(currentRowIndex, columns, tempBuffer, tempBufferIndex); } rows -= maxRows; } } if (tempBufferIndex > 0) { stream.Write(tempBuffer, 0, tempBufferIndex); } if (tablesPos + totalSize != stream.Position) { throw new InvalidOperationException(); } }