summaryrefslogtreecommitdiff
path: root/utils/mapsorter/MapFileLoader.cs
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/mapsorter/MapFileLoader.cs
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'utils/mapsorter/MapFileLoader.cs')
-rw-r--r--utils/mapsorter/MapFileLoader.cs248
1 files changed, 248 insertions, 0 deletions
diff --git a/utils/mapsorter/MapFileLoader.cs b/utils/mapsorter/MapFileLoader.cs
new file mode 100644
index 0000000..a77b194
--- /dev/null
+++ b/utils/mapsorter/MapFileLoader.cs
@@ -0,0 +1,248 @@
+using System;
+using System.Text.RegularExpressions;
+using System.Collections;
+using System.IO;
+
+namespace MapSorter
+{
+ public class Element : IComparable
+ {
+ /// <summary>
+ /// Segment this element is in.
+ /// </summary>
+ public int Segment;
+
+ /// <summary>
+ /// Base or virtual file address.
+ /// </summary>
+ public int Address;
+
+ /// <summary>
+ /// Adjusted relative virtual address.
+ /// </summary>
+ public int RVA;
+
+ /// <summary>
+ /// Name of this element.
+ /// </summary>
+ public string Text;
+
+ /// <summary>
+ /// Object file this element is located in.
+ /// </summary>
+ public string Obj;
+
+ /// <summary>
+ /// Size of this element, or -1.
+ /// </summary>
+ public int Size = -1;
+
+ /// <summary>
+ /// True if this is the last element in an object file.
+ /// </summary>
+ public bool bCrossObj = false;
+
+ public Element( int Segment, int Address, string Text, int RVA, string Obj )
+ {
+ this.Segment = Segment;
+ this.Address = Address;
+ this.RVA = RVA;
+ this.Text = Text;
+ this.Obj = Obj;
+ }
+
+ // Comparable interface:
+ int System.IComparable.CompareTo( object o )
+ {
+ // HACK HACK - sorts according to size if size field is non negative, otherwise sorts by segment then address
+ Element other = (Element)o;
+
+ // Sort by size:
+ if( other.Size != -1 || Size != -1 )
+ {
+ if( Size < other.Size )
+ return -1;
+
+ if( Size > other.Size )
+ return 1;
+
+ return 0;
+ }
+
+ // Sizes aren't defined, sort by Segment then Address:
+ if( Segment != other.Segment )
+ {
+ if( Segment < other.Segment )
+ return -1;
+ else
+ return 0;
+ }
+
+ if( Address < other.Address )
+ return -1;
+ else if( Address > other.Address )
+ return 1;
+
+ return 0;
+ }
+ }
+
+ public class Module : IComparable
+ {
+ public string Name;
+ public int Size;
+
+ public Module(string Name, int Size)
+ {
+ this.Name = Name;
+ this.Size = Size;
+ }
+
+ int System.IComparable.CompareTo( object o )
+ {
+ Module m = (Module)o;
+ if( Size < m.Size )
+ return -1;
+
+ if( Size > m.Size )
+ return 1;
+ return 0;
+ }
+ }
+
+ /// <summary>
+ /// An atomic class that loads and parses a given map file.
+ /// </summary>
+ public class MapFileLoader
+ {
+ ArrayList Elements;
+ ArrayList Modules;
+
+ /// <summary>
+ /// Regular expression to break mapfile elements up:
+ /// </summary>
+ protected static Regex ElementRegex = new Regex(@"([0-9a-fA-F]{4})\:([0-9a-fA-F]{8})\s+([^\s]*)\s+([0-9a-fA-F]{8})\s(f\s)?(i\s)?\s+(.*\.obj)",RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase );
+
+
+ public MapFileLoader( string filename )
+ {
+ // Load the element data from the mapfile:
+ LoadElements( new StreamReader(filename).ReadToEnd() );
+
+ // Compute modules and their sizes:
+ ComputeModules();
+ }
+
+ public void DumpReport()
+ {
+ Console.WriteLine("***** Elements by size ascending. (*) = element straddles an .obj file boundary, so the size may not be correct.");
+ Console.WriteLine();
+
+ foreach (Element e in Elements )
+ {
+ if( e.Size < 1024 )
+ continue;
+
+ if( e.bCrossObj )
+ Console.Write("(*)");
+
+ Console.WriteLine( e.Size / 1024 + "k : " +e.Obj + " : " + e.Text );
+ }
+
+ Console.WriteLine();
+ Console.WriteLine();
+ Console.WriteLine("***** Modules by size, ascending. This is estimated based on elements that don't straddle .obj boundaries.");
+ Console.WriteLine();
+
+ foreach(Module m in Modules )
+ {
+ if( m.Size < 1024 )
+ continue;
+
+ Console.WriteLine( m.Size / 1024 + "k : " + m.Name );
+ }
+
+
+ }
+
+ protected void LoadElements( string mapfile )
+ {
+ // Match each appropriate line in the map file. The summary entries at the top of each map file are NOT matched by this regex.
+ MatchCollection matches = ElementRegex.Matches(mapfile);
+
+
+ Elements = new ArrayList();
+
+ // Convert each match to an Element type and add them to an array list.
+ foreach( Match m in matches )
+ {
+
+ Element e = new Element(int.Parse(m.Groups[1].Value,System.Globalization.NumberStyles.AllowHexSpecifier),
+ int.Parse(m.Groups[2].Value,System.Globalization.NumberStyles.AllowHexSpecifier),
+ m.Groups[3].Value,
+ int.Parse(m.Groups[4].Value,System.Globalization.NumberStyles.AllowHexSpecifier),
+ m.Groups[7].Value);
+
+ Elements.Add(e);
+
+ }
+
+ // Sort the list by address:
+ Elements.Sort();
+
+ Element previous = null;
+
+ // Compute estimated sizes for each element in the list:
+ foreach( Element e in Elements )
+ {
+ if( previous != null )
+ {
+ if( e.Segment == previous.Segment )
+ {
+ previous.Size = e.Address- previous.Address;
+
+ // Take note of the symbols that cross object file boundaries:
+ if( !previous.Obj.Equals(e.Obj) )
+ {
+ previous.bCrossObj = true;
+ }
+ }
+ }
+
+ previous = e;
+ }
+
+ // Sort the list by size
+ Elements.Sort();
+
+
+ }
+
+ protected void ComputeModules()
+ {
+ // Estimate the size of each object file:
+ Hashtable h = new Hashtable();
+
+ foreach(Element e in Elements )
+ {
+ if( !h.ContainsKey(e.Obj) )
+ h.Add(e.Obj,0);
+
+ if( !e.bCrossObj )
+ {
+ h[e.Obj] = (int)h[e.Obj] + e.Size;
+ }
+ }
+
+ Modules = new ArrayList();
+
+ foreach( string key in h.Keys )
+ {
+ Modules.Add( new Module(key, (int)h[key] ));
+ }
+
+ Modules.Sort();
+ }
+
+ }
+}