diff --git a/aclogview/App.config b/aclogview/App.config index 3b876bf..c77fd48 100644 --- a/aclogview/App.config +++ b/aclogview/App.config @@ -10,12 +10,18 @@ - - - - - 0 - + + + + + 0 + + + + + + + \ No newline at end of file diff --git a/aclogview/CM_Physics.cs b/aclogview/CM_Physics.cs index b1ccf94..5eae21d 100644 --- a/aclogview/CM_Physics.cs +++ b/aclogview/CM_Physics.cs @@ -426,7 +426,7 @@ public void contributeToTreeNode(TreeNode node) { } TreeNode timestampsNode = node.Nodes.Add("timestamps = "); for (int i = 0; i < timestamps.Length; ++i) { - timestampsNode.Nodes.Add(timestamps[i].ToString()); + timestampsNode.Nodes.Add("[" + i + "] = " + timestamps[i]); } } } diff --git a/aclogview/Enums/Item.cs b/aclogview/Enums/Item.cs index 1c424d7..0933c1d 100644 --- a/aclogview/Enums/Item.cs +++ b/aclogview/Enums/Item.cs @@ -68,7 +68,7 @@ public enum ITEM_TYPE { TYPE_ITEM = 3013615, TYPE_REDIRECTABLE_ITEM_ENCHANTMENT_TARGET = 33031, TYPE_ITEM_ENCHANTABLE_TARGET = 560015, - TYPE_SELF = 0, + //TYPE_SELF = 0, This is a duplicate of TYPE_UNDEF TYPE_VENDOR_SHOPKEEP = 1208248231, TYPE_VENDOR_GROCER = 4481568 } diff --git a/aclogview/FindOpcodeInFilesForm.Designer.cs b/aclogview/FindOpcodeInFilesForm.Designer.cs index 3a55efb..9837fa1 100644 --- a/aclogview/FindOpcodeInFilesForm.Designer.cs +++ b/aclogview/FindOpcodeInFilesForm.Designer.cs @@ -31,6 +31,7 @@ private void InitializeComponent() this.components = new System.ComponentModel.Container(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); this.txtSearchPathRoot = new System.Windows.Forms.TextBox(); this.label1 = new System.Windows.Forms.Label(); this.btnStartSearch = new System.Windows.Forms.Button(); @@ -38,12 +39,15 @@ private void InitializeComponent() this.btnChangeSearchPathRoot = new System.Windows.Forms.Button(); this.dataGridView1 = new System.Windows.Forms.DataGridView(); this.columnHits = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.columnExceptions = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.columnFileSize = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.columnFilePath = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.label2 = new System.Windows.Forms.Label(); this.txtOpcode = new System.Windows.Forms.TextBox(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabel2 = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabel3 = new System.Windows.Forms.ToolStripStatusLabel(); this.timer1 = new System.Windows.Forms.Timer(this.components); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); @@ -117,6 +121,7 @@ private void InitializeComponent() this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this.columnHits, + this.columnExceptions, this.columnFileSize, this.columnFilePath}); this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill; @@ -137,11 +142,21 @@ private void InitializeComponent() this.columnHits.ReadOnly = true; this.columnHits.Width = 60; // - // columnFileSize + // columnExceptions // dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; dataGridViewCellStyle2.Format = "N0"; - this.columnFileSize.DefaultCellStyle = dataGridViewCellStyle2; + this.columnExceptions.DefaultCellStyle = dataGridViewCellStyle2; + this.columnExceptions.HeaderText = "Exceptions"; + this.columnExceptions.Name = "columnExceptions"; + this.columnExceptions.ReadOnly = true; + this.columnExceptions.Width = 60; + // + // columnFileSize + // + dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle3.Format = "N0"; + this.columnFileSize.DefaultCellStyle = dataGridViewCellStyle3; this.columnFileSize.HeaderText = "File Size"; this.columnFileSize.Name = "columnFileSize"; this.columnFileSize.ReadOnly = true; @@ -174,7 +189,9 @@ private void InitializeComponent() // statusStrip1 // this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripStatusLabel1}); + this.toolStripStatusLabel1, + this.toolStripStatusLabel2, + this.toolStripStatusLabel3}); this.statusStrip1.Location = new System.Drawing.Point(0, 539); this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Size = new System.Drawing.Size(784, 22); @@ -187,6 +204,20 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(89, 17); this.toolStripStatusLabel1.Text = "Files Processed:"; // + // toolStripStatusLabel2 + // + this.toolStripStatusLabel2.Margin = new System.Windows.Forms.Padding(20, 3, 0, 2); + this.toolStripStatusLabel2.Name = "toolStripStatusLabel2"; + this.toolStripStatusLabel2.Size = new System.Drawing.Size(60, 17); + this.toolStripStatusLabel2.Text = "Total Hits:"; + // + // toolStripStatusLabel3 + // + this.toolStripStatusLabel3.Margin = new System.Windows.Forms.Padding(20, 3, 0, 2); + this.toolStripStatusLabel3.Name = "toolStripStatusLabel3"; + this.toolStripStatusLabel3.Size = new System.Drawing.Size(92, 17); + this.toolStripStatusLabel3.Text = "Frag Exceptions:"; + // // timer1 // this.timer1.Interval = 200; @@ -277,12 +308,15 @@ private void InitializeComponent() private System.Windows.Forms.StatusStrip statusStrip1; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; private System.Windows.Forms.Timer timer1; - private System.Windows.Forms.DataGridViewTextBoxColumn columnHits; - private System.Windows.Forms.DataGridViewTextBoxColumn columnFileSize; - private System.Windows.Forms.DataGridViewTextBoxColumn columnFilePath; private System.Windows.Forms.TabControl tabControl1; private System.Windows.Forms.TabPage tabPage1; private System.Windows.Forms.TabPage tabPage2; private System.Windows.Forms.RichTextBox richTextBox1; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel2; + private System.Windows.Forms.DataGridViewTextBoxColumn columnHits; + private System.Windows.Forms.DataGridViewTextBoxColumn columnExceptions; + private System.Windows.Forms.DataGridViewTextBoxColumn columnFileSize; + private System.Windows.Forms.DataGridViewTextBoxColumn columnFilePath; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel3; } } \ No newline at end of file diff --git a/aclogview/FindOpcodeInFilesForm.cs b/aclogview/FindOpcodeInFilesForm.cs index fcf2421..0f8d1d8 100644 --- a/aclogview/FindOpcodeInFilesForm.cs +++ b/aclogview/FindOpcodeInFilesForm.cs @@ -75,12 +75,15 @@ private void btnChangeSearchPathRoot_Click(object sender, EventArgs e) private readonly List filesToProcess = new List(); private int opCodeToSearchFor; private int filesProcessed; + private int totalHits; + private int totalExceptions; private bool searchAborted; private class ProcessFileResut { - public int Hits; public string FileName; + public int Hits; + public int Exceptions; } private readonly ConcurrentBag processFileResuts = new ConcurrentBag(); @@ -99,6 +102,8 @@ private void btnStartSearch_Click(object sender, EventArgs e) filesToProcess.Clear(); opCodeToSearchFor = OpCode; filesProcessed = 0; + totalHits = 0; + totalExceptions = 0; searchAborted = false; ProcessFileResut result; @@ -176,113 +181,135 @@ private void DoSearch() private void ProcessFile(string fileName) { int hits = 0; + int exceptions = 0; var records = PCapReader.LoadPcap(fileName, ref searchAborted); - // We could put the abort check in the foreach, but the only downside to having it here is if you abort/close during a huge log parse, you have to wait a few seconds for the log to finish - // before the app actually terminates. - if (searchAborted || Disposing || IsDisposed) - return; - foreach (var record in records) { + if (searchAborted || Disposing || IsDisposed) + return; + if (record.opcodes.Contains((PacketOpcode)opCodeToSearchFor)) + { hits++; + Interlocked.Increment(ref totalHits); + } + + // ******************************************************************** + // ************************ CUSTOM SEARCH CODE ************************ + // ******************************************************************** // Custom search code that can output information to Special Output + // Below are several commented out examples on how you can search through bulk pcaps for targeted data, and output detailed information to the output tab. foreach (BlobFrag frag in record.netPacket.fragList_) { - if (frag.dat_.Length <= 20) // ITS IMPORTANT THAT YOU MAKE SURE YOU HAVE THE CORRECT LENGTH HERE. If your target is shorter than this, it will be skipped - continue; - - BinaryReader fragDataReader = new BinaryReader(new MemoryStream(frag.dat_)); - - var messageCode = fragDataReader.ReadUInt32(); - - /*if (messageCode == 0x02BB) // Creature Message + try { - var parsed = CM_Communication.HearSpeech.read(fragDataReader); + if (frag.dat_.Length <= 4) + continue; - //if (parsed.ChatMessageType != 0x0C) - // continue; + BinaryReader fragDataReader = new BinaryReader(new MemoryStream(frag.dat_)); - var output = parsed.ChatMessageType.ToString("X4") + " " + parsed.MessageText; + var messageCode = fragDataReader.ReadUInt32(); - if (!specialOutputHits.ContainsKey(output)) + /*if (messageCode == 0x02BB) // Creature Message { - if (specialOutputHits.TryAdd(output, 0)) - specialOutputHitsQueue.Enqueue(output); - } - }*/ + var parsed = CM_Communication.HearSpeech.read(fragDataReader); - /*if (messageCode == 0xF7B0) // Game Event - { - var character = fragDataReader.ReadUInt32(); // Character - var sequence = fragDataReader.ReadUInt32(); // Sequence - var _event = fragDataReader.ReadUInt32(); // Event + //if (parsed.ChatMessageType != 0x0C) + // continue; - if (_event == 0x0147) // Group Chat - { - var parsed = CM_Communication.ChannelBroadcast.read(fragDataReader); + var output = parsed.ChatMessageType.ToString("X4") + " " + parsed.MessageText; - var output = parsed.GroupChatType.ToString("X4"); if (!specialOutputHits.ContainsKey(output)) { if (specialOutputHits.TryAdd(output, 0)) specialOutputHitsQueue.Enqueue(output); } - } + }*/ - if (_event == 0x02BD) // Tell + /*if (messageCode == 0xF745) // Create Object { - var parsed = CM_Communication.HearDirectSpeech.read(fragDataReader); + var parsed = CM_Physics.CreateObject.read(fragDataReader); + }*/ - var output = parsed.ChatMessageType.ToString("X4"); + /*if (messageCode == 0xF7B0) // Game Event + { + var character = fragDataReader.ReadUInt32(); // Character + var sequence = fragDataReader.ReadUInt32(); // Sequence + var _event = fragDataReader.ReadUInt32(); // Event - if (!specialOutputHits.ContainsKey(output)) + if (_event == 0x0147) // Group Chat { - if (specialOutputHits.TryAdd(output, 0)) - specialOutputHitsQueue.Enqueue(output); + var parsed = CM_Communication.ChannelBroadcast.read(fragDataReader); + + var output = parsed.GroupChatType.ToString("X4"); + if (!specialOutputHits.ContainsKey(output)) + { + if (specialOutputHits.TryAdd(output, 0)) + specialOutputHitsQueue.Enqueue(output); + } } - } - }*/ - /*if (messageCode == 0xF7B1) // Game Action - { - }*/ + if (_event == 0x02BD) // Tell + { + var parsed = CM_Communication.HearDirectSpeech.read(fragDataReader); - /*if (messageCode == 0xF7DE) // TurbineChat - { - var parsed = CM_Admin.ChatServerData.read(fragDataReader); + var output = parsed.ChatMessageType.ToString("X4"); - string output = parsed.TurbineChatType.ToString("X2"); + if (!specialOutputHits.ContainsKey(output)) + { + if (specialOutputHits.TryAdd(output, 0)) + specialOutputHitsQueue.Enqueue(output); + } + } + }*/ - if (!specialOutputHits.ContainsKey(output)) + /*if (messageCode == 0xF7B1) // Game Action { - if (specialOutputHits.TryAdd(output, 0)) - specialOutputHitsQueue.Enqueue(output); - } - }*/ + }*/ - /*if (messageCode == 0xF7E0) // Server Message - { - var parsed = CM_Communication.TextBoxString.read(fragDataReader); + /*if (messageCode == 0xF7DE) // TurbineChat + { + var parsed = CM_Admin.ChatServerData.read(fragDataReader); - //var output = parsed.ChatMessageType.ToString("X4") + " " + parsed.MessageText + ","; - var output = parsed.ChatMessageType.ToString("X4"); + string output = parsed.TurbineChatType.ToString("X2"); - if (!specialOutputHits.ContainsKey(output)) + if (!specialOutputHits.ContainsKey(output)) + { + if (specialOutputHits.TryAdd(output, 0)) + specialOutputHitsQueue.Enqueue(output); + } + }*/ + + /*if (messageCode == 0xF7E0) // Server Message { - if (specialOutputHits.TryAdd(output, 0)) - specialOutputHitsQueue.Enqueue(output); - } - }*/ + var parsed = CM_Communication.TextBoxString.read(fragDataReader); + + //var output = parsed.ChatMessageType.ToString("X4") + " " + parsed.MessageText + ","; + var output = parsed.ChatMessageType.ToString("X4"); + + if (!specialOutputHits.ContainsKey(output)) + { + if (specialOutputHits.TryAdd(output, 0)) + specialOutputHitsQueue.Enqueue(output); + } + }*/ + } + catch + { + // Do something with the exception maybe + exceptions++; + + Interlocked.Increment(ref totalExceptions); + } } } Interlocked.Increment(ref filesProcessed); - processFileResuts.Add(new ProcessFileResut() { Hits = hits, FileName = fileName }); + processFileResuts.Add(new ProcessFileResut() { FileName = fileName, Hits = hits, Exceptions = exceptions }); } private void timer1_Tick(object sender, EventArgs e) @@ -294,8 +321,8 @@ private void timer1_Tick(object sender, EventArgs e) { var length = new FileInfo(result.FileName).Length; - if (result.Hits > 0) - dataGridView1.Rows.Add(result.Hits, length, result.FileName); + if (result.Hits > 0 || result.Exceptions > 0) + dataGridView1.Rows.Add(result.Hits, result.Exceptions, length, result.FileName); } } @@ -306,7 +333,11 @@ private void timer1_Tick(object sender, EventArgs e) richTextBox1.Text += specialOutputHitsQueueResult + Environment.NewLine; } - toolStripStatusLabel1.Text = "Files Processed: " + filesProcessed + " of " + filesToProcess.Count; + toolStripStatusLabel1.Text = "Files Processed: " + filesProcessed.ToString("N0") + " of " + filesToProcess.Count.ToString("N0"); + + toolStripStatusLabel2.Text = "Total Hits: " + totalHits.ToString("N0"); + + toolStripStatusLabel3.Text = "Frag Exceptions: " + totalExceptions.ToString("N0"); } @@ -315,7 +346,7 @@ private void dataGridView1_CellContentDoubleClick(object sender, DataGridViewCel if (e.RowIndex == -1) return; - var fileName = (string)dataGridView1.Rows[e.RowIndex].Cells[2].Value; + var fileName = (string)dataGridView1.Rows[e.RowIndex].Cells[3].Value; System.Diagnostics.Process.Start(Application.ExecutablePath, '"' + fileName + '"' + " " + opCodeToSearchFor); } diff --git a/aclogview/FindOpcodeInFilesForm.resx b/aclogview/FindOpcodeInFilesForm.resx index 846ffc6..f53f5e7 100644 --- a/aclogview/FindOpcodeInFilesForm.resx +++ b/aclogview/FindOpcodeInFilesForm.resx @@ -120,6 +120,9 @@ True + + True + True diff --git a/aclogview/Form1.Designer.cs b/aclogview/Form1.Designer.cs index 69e5388..57e5732 100644 --- a/aclogview/Form1.Designer.cs +++ b/aclogview/Form1.Designer.cs @@ -40,6 +40,7 @@ private void InitializeComponent() { this.menuItem_File = new System.Windows.Forms.MenuItem(); this.menuItem_Open = new System.Windows.Forms.MenuItem(); this.menuItem_Edit = new System.Windows.Forms.MenuItem(); + this.mnuItem_EditPreviousHighlightedRow = new System.Windows.Forms.MenuItem(); this.mnuItem_EditNextHighlightedRow = new System.Windows.Forms.MenuItem(); this.menuItem1 = new System.Windows.Forms.MenuItem(); this.menuItem_ToolCount = new System.Windows.Forms.MenuItem(); @@ -54,7 +55,8 @@ private void InitializeComponent() { this.statusStrip = new System.Windows.Forms.StatusStrip(); this.checkBox_HideHeaderOnly = new System.Windows.Forms.CheckBox(); this.checkBox_useHighlighting = new System.Windows.Forms.CheckBox(); - this.mnuItem_EditPreviousHighlightedRow = new System.Windows.Forms.MenuItem(); + this.menuItem2 = new System.Windows.Forms.MenuItem(); + this.mnuItem_ToolFragDatListTool = new System.Windows.Forms.MenuItem(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer_Main)).BeginInit(); this.splitContainer_Main.Panel1.SuspendLayout(); this.splitContainer_Main.Panel2.SuspendLayout(); @@ -213,6 +215,13 @@ private void InitializeComponent() { this.mnuItem_EditNextHighlightedRow}); this.menuItem_Edit.Text = "Edit"; // + // mnuItem_EditPreviousHighlightedRow + // + this.mnuItem_EditPreviousHighlightedRow.Index = 0; + this.mnuItem_EditPreviousHighlightedRow.Shortcut = System.Windows.Forms.Shortcut.ShiftF3; + this.mnuItem_EditPreviousHighlightedRow.Text = "Previous Highlighted Row"; + this.mnuItem_EditPreviousHighlightedRow.Click += new System.EventHandler(this.mnuItem_EditPreviousHighlightedRow_Click); + // // mnuItem_EditNextHighlightedRow // this.mnuItem_EditNextHighlightedRow.Index = 1; @@ -227,7 +236,9 @@ private void InitializeComponent() { this.menuItem_ToolCount, this.menuItem_ToolBad, this.menuItem_ToolHeatmap, - this.mnuItem_ToolFindOpcodeInFiles}); + this.menuItem2, + this.mnuItem_ToolFindOpcodeInFiles, + this.mnuItem_ToolFragDatListTool}); this.menuItem1.Text = "Tools"; // // menuItem_ToolCount @@ -250,7 +261,7 @@ private void InitializeComponent() { // // mnuItem_ToolFindOpcodeInFiles // - this.mnuItem_ToolFindOpcodeInFiles.Index = 3; + this.mnuItem_ToolFindOpcodeInFiles.Index = 4; this.mnuItem_ToolFindOpcodeInFiles.Text = "Find Opcode In Files"; this.mnuItem_ToolFindOpcodeInFiles.Click += new System.EventHandler(this.mnuItem_ToolFindOpcodeInFiles_Click); // @@ -323,12 +334,16 @@ private void InitializeComponent() { this.checkBox_useHighlighting.UseVisualStyleBackColor = true; this.checkBox_useHighlighting.CheckedChanged += new System.EventHandler(this.checkBox_useHighlighting_CheckedChanged); // - // mnuItem_EditPreviousHighlightedRow + // menuItem2 // - this.mnuItem_EditPreviousHighlightedRow.Index = 0; - this.mnuItem_EditPreviousHighlightedRow.Shortcut = System.Windows.Forms.Shortcut.ShiftF3; - this.mnuItem_EditPreviousHighlightedRow.Text = "Previous Highlighted Row"; - this.mnuItem_EditPreviousHighlightedRow.Click += new System.EventHandler(this.mnuItem_EditPreviousHighlightedRow_Click); + this.menuItem2.Index = 3; + this.menuItem2.Text = "-"; + // + // mnuItem_ToolFragDatListTool + // + this.mnuItem_ToolFragDatListTool.Index = 5; + this.mnuItem_ToolFragDatListTool.Text = "Frag Dat List Tool"; + this.mnuItem_ToolFragDatListTool.Click += new System.EventHandler(this.mnuItem_ToolFragDatListTool_Click); // // Form1 // @@ -394,6 +409,8 @@ private void InitializeComponent() { private System.Windows.Forms.MenuItem mnuItem_ToolFindOpcodeInFiles; private System.Windows.Forms.MenuItem mnuItem_EditNextHighlightedRow; private System.Windows.Forms.MenuItem mnuItem_EditPreviousHighlightedRow; + private System.Windows.Forms.MenuItem menuItem2; + private System.Windows.Forms.MenuItem mnuItem_ToolFragDatListTool; } } diff --git a/aclogview/Form1.cs b/aclogview/Form1.cs index 027ad16..260ce7b 100644 --- a/aclogview/Form1.cs +++ b/aclogview/Form1.cs @@ -1013,6 +1013,12 @@ private void mnuItem_ToolFindOpcodeInFiles_Click(object sender, EventArgs e) form.Show(this); } + private void mnuItem_ToolFragDatListTool_Click(object sender, EventArgs e) + { + var form = new FragDatListToolForm(); + form.Show(this); + } + private void menuItem_About_Click(object sender, EventArgs e) { MessageBox.Show("aclogview\n\nA program to view and parse Asheron's Call 1 packet capture files (.pcap) generated by aclog.\n\nFor more info and source code, see https://github.com/tfarley/aclogview", "About"); diff --git a/aclogview/FragDatListFile.cs b/aclogview/FragDatListFile.cs new file mode 100644 index 0000000..dfbc438 --- /dev/null +++ b/aclogview/FragDatListFile.cs @@ -0,0 +1,280 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Windows.Forms; + +namespace aclogview +{ + class FragDatListFile + { + private static readonly byte FileVersion = 0x01; + + public enum CompressionType : byte + { + None = 0x00, + DeflateStream = 0x01 + } + + public enum PacketDirection : byte + { + ServerToClient = 0x00, + ClientToServer = 0x01 + } + + public class FragDatInfo + { + public PacketDirection PacketDirection; + + public int ReferenceIndex; + + public byte[] Data; + + public FragDatInfo(PacketDirection packetDirection, int referenceIndex, byte[] data) + { + PacketDirection = packetDirection; + ReferenceIndex = referenceIndex; + Data = data; + } + } + + + private FileStream fileStream; + private byte workingFileVersion; + private CompressionType workingCompressionType; + + /// + /// Will prompt the user for a path. + /// Use Write() to add data to the file, and CloseFile when you're finished. + /// + public bool CreateFile(CompressionType compressionType = CompressionType.DeflateStream) + { + string fileName; + + using (SaveFileDialog newDialog = new SaveFileDialog()) + { + newDialog.Filter = "Frag Dat List (*.frags)|*.frags"; + newDialog.DefaultExt = ".frags"; + + if (newDialog.ShowDialog() != DialogResult.OK) + return false; + + fileName = newDialog.FileName; + + if (String.IsNullOrEmpty(fileName)) + return false; + } + + return OpenFile(fileName); + } + + /// + /// Use Write() to add data to the file, and CloseFile when you're finished. + /// If the specified file already exists, it will be overwritten. + /// + public bool CreateFile(string fileName, CompressionType compressionType = CompressionType.DeflateStream) + { + fileStream = File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.None); + workingFileVersion = FileVersion; + workingCompressionType = compressionType; + + using (BinaryWriter fileWriter = new BinaryWriter(fileStream, System.Text.Encoding.Default, true)) + { + fileWriter.Write(FileVersion); + fileWriter.Write((byte)compressionType); + } + + return fileStream != null; + } + + /// + /// Use CreateFile() first. + /// This function is not thread safe. + /// + public bool Write(KeyValuePair> fragDatInfos) + { + if (fileStream == null) + return false; + + + // Setup the writer + MemoryStream memoryStream = null; // Used if we're not writing ot the file directly + BinaryWriter writer; // This will either write to the base fileStream, or to memoryStream + + if (workingCompressionType == CompressionType.None) + writer = new BinaryWriter(fileStream, System.Text.Encoding.Default, true); + else if (workingCompressionType == CompressionType.DeflateStream) + { + memoryStream = new MemoryStream(); + writer = new BinaryWriter(memoryStream, System.Text.Encoding.Default, true); + } + else + throw new NotImplementedException(); + + + // Write + writer.Write(fragDatInfos.Key ?? String.Empty); + + writer.Write(fragDatInfos.Value.Count); + + foreach (var fragDatInfo in fragDatInfos.Value) + { + writer.Write((byte)fragDatInfo.PacketDirection); + writer.Write(fragDatInfo.ReferenceIndex); + writer.Write((UInt16)fragDatInfo.Data.Length); + writer.Write(fragDatInfo.Data); + } + + + // Transfer memoryStream to fileStream if we need to + if (workingCompressionType == CompressionType.DeflateStream) + { + using (MemoryStream compressedMemoryStream = new MemoryStream()) + { + using (DeflateStream deflateStream = new DeflateStream(compressedMemoryStream, CompressionMode.Compress, true)) + memoryStream.WriteTo(deflateStream); + + if (compressedMemoryStream.Length > UInt32.MaxValue) throw new OverflowException(); + fileStream.Write(new byte[] { (byte)(compressedMemoryStream.Length >> 0), (byte)(compressedMemoryStream.Length >> 8), (byte)(compressedMemoryStream.Length >> 16), (byte)(compressedMemoryStream.Length >> 24) }, 0, 4); + compressedMemoryStream.WriteTo(fileStream); + } + } + + + // Close the writer + writer.Dispose(); + + if (memoryStream != null) + memoryStream.Dispose(); + + + return true; + } + + + /// + /// Will prompt the user for a path. + /// Use ReadNext to read data from the file, and CloseFile when you're finished. + /// This will return null when the end of the file has been reached. + /// + public bool OpenFile() + { + string fileName; + + using (OpenFileDialog newDialog = new OpenFileDialog()) + { + newDialog.Filter = "Frag Dat List (*.frags)|*.frags"; + newDialog.DefaultExt = ".frags"; + + if (newDialog.ShowDialog() != DialogResult.OK) + return false; + + fileName = newDialog.FileName; + + if (String.IsNullOrEmpty(fileName)) + return false; + } + + return OpenFile(fileName); + } + + /// + /// Use ReadNext to read data from the file, and CloseFile when you're finished. + /// This will return null when the end of the file has been reached. + /// + public bool OpenFile(string fileName) + { + fileStream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); + + workingFileVersion = (byte)fileStream.ReadByte(); + workingCompressionType = (CompressionType)fileStream.ReadByte(); + + return fileStream != null; + } + + /// + /// OpenFile() first. + /// This function is not thread safe. + /// + public bool TryReadNext(out KeyValuePair> kvp) + { + try + { + using (BinaryReader reader = new BinaryReader(fileStream, System.Text.Encoding.Default, true)) + { + if (workingFileVersion != 1) + throw new NotSupportedException(); + + string key; + var fragDataInfos = new List(); + + if (workingCompressionType == CompressionType.None) + { + key = reader.ReadString(); + + var count = reader.ReadInt32(); + + for (int i = 0; i < count; i++) + { + var packetDirection = (PacketDirection)reader.ReadByte(); + + var referenceIndex = reader.ReadInt32(); + + var byteCount = reader.ReadUInt16(); + var bytes = reader.ReadBytes(byteCount); + + fragDataInfos.Add(new FragDatInfo(packetDirection, referenceIndex, bytes)); + } + } + else if (workingCompressionType == CompressionType.DeflateStream) + { + int compressedDataSize = reader.ReadInt32(); + byte[] compressedData = new byte[compressedDataSize]; + reader.Read(compressedData, 0, compressedDataSize); + + using (MemoryStream compressedDataStream = new MemoryStream(compressedData)) + using (DeflateStream deflateStream = new DeflateStream(compressedDataStream, CompressionMode.Decompress)) + using (BinaryReader deflateReader = new BinaryReader(deflateStream)) + { + key = deflateReader.ReadString(); + + var count = deflateReader.ReadInt32(); + + for (int i = 0; i < count; i++) + { + var packetDirection = (PacketDirection)deflateReader.ReadByte(); + + var referenceIndex = deflateReader.ReadInt32(); + + var byteCount = deflateReader.ReadUInt16(); + var bytes = deflateReader.ReadBytes(byteCount); + + fragDataInfos.Add(new FragDatInfo(packetDirection, referenceIndex, bytes)); + } + } + } + else + throw new NotImplementedException(); + + kvp = new KeyValuePair>(key, fragDataInfos); + return true; + } + } + catch + { + kvp = new KeyValuePair>(); + return false; + } + } + + + public void CloseFile() + { + if (fileStream != null) + { + fileStream.Close(); + fileStream = null; + } + } + } +} diff --git a/aclogview/FragDatListToolForm.Designer.cs b/aclogview/FragDatListToolForm.Designer.cs new file mode 100644 index 0000000..744392f --- /dev/null +++ b/aclogview/FragDatListToolForm.Designer.cs @@ -0,0 +1,372 @@ +namespace aclogview +{ + partial class FragDatListToolForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.groupBoxFragDatListFileBuilder = new System.Windows.Forms.GroupBox(); + this.btnStopBuild = new System.Windows.Forms.Button(); + this.btnChangeSearchPathRoot = new System.Windows.Forms.Button(); + this.btnStartBuild = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.txtSearchPathRoot = new System.Windows.Forms.TextBox(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabel2 = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabel3 = new System.Windows.Forms.ToolStripStatusLabel(); + this.timer1 = new System.Windows.Forms.Timer(this.components); + this.label2 = new System.Windows.Forms.Label(); + this.groupBoxProcessFragDatListFile = new System.Windows.Forms.GroupBox(); + this.btnStopProcess = new System.Windows.Forms.Button(); + this.btnChangeFileToProcess = new System.Windows.Forms.Button(); + this.label3 = new System.Windows.Forms.Label(); + this.txtFileToProcess = new System.Windows.Forms.TextBox(); + this.btnStartProcess = new System.Windows.Forms.Button(); + this.btnChangeOutputFolder = new System.Windows.Forms.Button(); + this.label4 = new System.Windows.Forms.Label(); + this.txtOutputFolder = new System.Windows.Forms.TextBox(); + this.chkCompressOutput = new System.Windows.Forms.CheckBox(); + this.chkIncludeFullPathAndFileName = new System.Windows.Forms.CheckBox(); + this.groupBoxGeneralSettings = new System.Windows.Forms.GroupBox(); + this.toolStripStatusLabel4 = new System.Windows.Forms.ToolStripStatusLabel(); + this.groupBoxFragDatListFileBuilder.SuspendLayout(); + this.statusStrip1.SuspendLayout(); + this.groupBoxProcessFragDatListFile.SuspendLayout(); + this.groupBoxGeneralSettings.SuspendLayout(); + this.SuspendLayout(); + // + // groupBoxFragDatListFileBuilder + // + this.groupBoxFragDatListFileBuilder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBoxFragDatListFileBuilder.Controls.Add(this.chkIncludeFullPathAndFileName); + this.groupBoxFragDatListFileBuilder.Controls.Add(this.chkCompressOutput); + this.groupBoxFragDatListFileBuilder.Controls.Add(this.btnStopBuild); + this.groupBoxFragDatListFileBuilder.Controls.Add(this.btnChangeSearchPathRoot); + this.groupBoxFragDatListFileBuilder.Controls.Add(this.btnStartBuild); + this.groupBoxFragDatListFileBuilder.Controls.Add(this.label1); + this.groupBoxFragDatListFileBuilder.Controls.Add(this.txtSearchPathRoot); + this.groupBoxFragDatListFileBuilder.Location = new System.Drawing.Point(12, 103); + this.groupBoxFragDatListFileBuilder.Name = "groupBoxFragDatListFileBuilder"; + this.groupBoxFragDatListFileBuilder.Size = new System.Drawing.Size(760, 77); + this.groupBoxFragDatListFileBuilder.TabIndex = 0; + this.groupBoxFragDatListFileBuilder.TabStop = false; + this.groupBoxFragDatListFileBuilder.Text = "Frag Dat List File Builder"; + // + // btnStopBuild + // + this.btnStopBuild.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnStopBuild.Enabled = false; + this.btnStopBuild.Location = new System.Drawing.Point(633, 48); + this.btnStopBuild.Name = "btnStopBuild"; + this.btnStopBuild.Size = new System.Drawing.Size(121, 23); + this.btnStopBuild.TabIndex = 9; + this.btnStopBuild.Text = "Stop Build"; + this.btnStopBuild.UseVisualStyleBackColor = true; + this.btnStopBuild.Click += new System.EventHandler(this.btnStopBuild_Click); + // + // btnChangeSearchPathRoot + // + this.btnChangeSearchPathRoot.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnChangeSearchPathRoot.Location = new System.Drawing.Point(726, 19); + this.btnChangeSearchPathRoot.Name = "btnChangeSearchPathRoot"; + this.btnChangeSearchPathRoot.Size = new System.Drawing.Size(28, 23); + this.btnChangeSearchPathRoot.TabIndex = 8; + this.btnChangeSearchPathRoot.Text = "F"; + this.btnChangeSearchPathRoot.UseVisualStyleBackColor = true; + this.btnChangeSearchPathRoot.Click += new System.EventHandler(this.btnChangeSearchPathRoot_Click); + // + // btnStartBuild + // + this.btnStartBuild.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnStartBuild.Location = new System.Drawing.Point(506, 48); + this.btnStartBuild.Name = "btnStartBuild"; + this.btnStartBuild.Size = new System.Drawing.Size(121, 23); + this.btnStartBuild.TabIndex = 7; + this.btnStartBuild.Text = "Start Build"; + this.btnStartBuild.UseVisualStyleBackColor = true; + this.btnStartBuild.Click += new System.EventHandler(this.btnStartBuild_Click); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 25); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(92, 13); + this.label1.TabIndex = 6; + this.label1.Text = "Search Path Root"; + // + // txtSearchPathRoot + // + this.txtSearchPathRoot.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtSearchPathRoot.Location = new System.Drawing.Point(104, 22); + this.txtSearchPathRoot.Name = "txtSearchPathRoot"; + this.txtSearchPathRoot.Size = new System.Drawing.Size(616, 20); + this.txtSearchPathRoot.TabIndex = 5; + // + // statusStrip1 + // + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabel1, + this.toolStripStatusLabel2, + this.toolStripStatusLabel3, + this.toolStripStatusLabel4}); + this.statusStrip1.Location = new System.Drawing.Point(0, 539); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(784, 22); + this.statusStrip1.TabIndex = 9; + this.statusStrip1.Text = "statusStrip1"; + // + // toolStripStatusLabel1 + // + this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; + this.toolStripStatusLabel1.Size = new System.Drawing.Size(89, 17); + this.toolStripStatusLabel1.Text = "Files Processed:"; + // + // toolStripStatusLabel2 + // + this.toolStripStatusLabel2.Margin = new System.Windows.Forms.Padding(20, 3, 0, 2); + this.toolStripStatusLabel2.Name = "toolStripStatusLabel2"; + this.toolStripStatusLabel2.Size = new System.Drawing.Size(122, 17); + this.toolStripStatusLabel2.Text = "Fragments Processed:"; + // + // toolStripStatusLabel3 + // + this.toolStripStatusLabel3.Margin = new System.Windows.Forms.Padding(20, 3, 0, 2); + this.toolStripStatusLabel3.Name = "toolStripStatusLabel3"; + this.toolStripStatusLabel3.Size = new System.Drawing.Size(60, 17); + this.toolStripStatusLabel3.Text = "Total Hits:"; + // + // timer1 + // + this.timer1.Interval = 200; + this.timer1.Tick += new System.EventHandler(this.timer1_Tick); + // + // label2 + // + this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label2.Location = new System.Drawing.Point(12, 9); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(760, 36); + this.label2.TabIndex = 10; + this.label2.Text = "This tool is designed to run within Visual Studio. There are comments describing " + + "how you can adjust this tool to perform custom data mining tasks that you might " + + "need."; + // + // groupBoxProcessFragDatListFile + // + this.groupBoxProcessFragDatListFile.Controls.Add(this.btnStopProcess); + this.groupBoxProcessFragDatListFile.Controls.Add(this.btnChangeFileToProcess); + this.groupBoxProcessFragDatListFile.Controls.Add(this.label3); + this.groupBoxProcessFragDatListFile.Controls.Add(this.txtFileToProcess); + this.groupBoxProcessFragDatListFile.Controls.Add(this.btnStartProcess); + this.groupBoxProcessFragDatListFile.Location = new System.Drawing.Point(12, 186); + this.groupBoxProcessFragDatListFile.Name = "groupBoxProcessFragDatListFile"; + this.groupBoxProcessFragDatListFile.Size = new System.Drawing.Size(760, 339); + this.groupBoxProcessFragDatListFile.TabIndex = 11; + this.groupBoxProcessFragDatListFile.TabStop = false; + this.groupBoxProcessFragDatListFile.Text = "Process Frag Dat List File"; + // + // btnStopProcess + // + this.btnStopProcess.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnStopProcess.Enabled = false; + this.btnStopProcess.Location = new System.Drawing.Point(633, 48); + this.btnStopProcess.Name = "btnStopProcess"; + this.btnStopProcess.Size = new System.Drawing.Size(121, 23); + this.btnStopProcess.TabIndex = 12; + this.btnStopProcess.Text = "Stop Process"; + this.btnStopProcess.UseVisualStyleBackColor = true; + this.btnStopProcess.Click += new System.EventHandler(this.btnStopProcess_Click); + // + // btnChangeFileToProcess + // + this.btnChangeFileToProcess.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnChangeFileToProcess.Location = new System.Drawing.Point(726, 19); + this.btnChangeFileToProcess.Name = "btnChangeFileToProcess"; + this.btnChangeFileToProcess.Size = new System.Drawing.Size(28, 23); + this.btnChangeFileToProcess.TabIndex = 11; + this.btnChangeFileToProcess.Text = "F"; + this.btnChangeFileToProcess.UseVisualStyleBackColor = true; + this.btnChangeFileToProcess.Click += new System.EventHandler(this.btnChangeFileToProcess_Click); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 24); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(80, 13); + this.label3.TabIndex = 10; + this.label3.Text = "File To Process"; + // + // txtFileToProcess + // + this.txtFileToProcess.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtFileToProcess.Location = new System.Drawing.Point(104, 21); + this.txtFileToProcess.Name = "txtFileToProcess"; + this.txtFileToProcess.Size = new System.Drawing.Size(616, 20); + this.txtFileToProcess.TabIndex = 9; + // + // btnStartProcess + // + this.btnStartProcess.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnStartProcess.Location = new System.Drawing.Point(506, 47); + this.btnStartProcess.Name = "btnStartProcess"; + this.btnStartProcess.Size = new System.Drawing.Size(121, 23); + this.btnStartProcess.TabIndex = 8; + this.btnStartProcess.Text = "Start Process"; + this.btnStartProcess.UseVisualStyleBackColor = true; + this.btnStartProcess.Click += new System.EventHandler(this.btnStartProcess_Click); + // + // btnChangeOutputFolder + // + this.btnChangeOutputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnChangeOutputFolder.Location = new System.Drawing.Point(726, 19); + this.btnChangeOutputFolder.Name = "btnChangeOutputFolder"; + this.btnChangeOutputFolder.Size = new System.Drawing.Size(28, 23); + this.btnChangeOutputFolder.TabIndex = 12; + this.btnChangeOutputFolder.Text = "F"; + this.btnChangeOutputFolder.UseVisualStyleBackColor = true; + this.btnChangeOutputFolder.Click += new System.EventHandler(this.btnChangeOutputFolder_Click); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(6, 25); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(71, 13); + this.label4.TabIndex = 11; + this.label4.Text = "Output Folder"; + // + // txtOutputFolder + // + this.txtOutputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtOutputFolder.Location = new System.Drawing.Point(104, 22); + this.txtOutputFolder.Name = "txtOutputFolder"; + this.txtOutputFolder.Size = new System.Drawing.Size(616, 20); + this.txtOutputFolder.TabIndex = 10; + // + // chkCompressOutput + // + this.chkCompressOutput.AutoSize = true; + this.chkCompressOutput.Checked = true; + this.chkCompressOutput.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompressOutput.Location = new System.Drawing.Point(104, 48); + this.chkCompressOutput.Name = "chkCompressOutput"; + this.chkCompressOutput.Size = new System.Drawing.Size(107, 17); + this.chkCompressOutput.TabIndex = 13; + this.chkCompressOutput.Text = "Compress Output"; + this.chkCompressOutput.UseVisualStyleBackColor = true; + // + // chkIncludeFullPathAndFileName + // + this.chkIncludeFullPathAndFileName.AutoSize = true; + this.chkIncludeFullPathAndFileName.Location = new System.Drawing.Point(217, 48); + this.chkIncludeFullPathAndFileName.Name = "chkIncludeFullPathAndFileName"; + this.chkIncludeFullPathAndFileName.Size = new System.Drawing.Size(158, 17); + this.chkIncludeFullPathAndFileName.TabIndex = 14; + this.chkIncludeFullPathAndFileName.Text = "Include Full Path+File Name"; + this.chkIncludeFullPathAndFileName.UseVisualStyleBackColor = true; + // + // groupBoxGeneralSettings + // + this.groupBoxGeneralSettings.Controls.Add(this.btnChangeOutputFolder); + this.groupBoxGeneralSettings.Controls.Add(this.txtOutputFolder); + this.groupBoxGeneralSettings.Controls.Add(this.label4); + this.groupBoxGeneralSettings.Location = new System.Drawing.Point(12, 48); + this.groupBoxGeneralSettings.Name = "groupBoxGeneralSettings"; + this.groupBoxGeneralSettings.Size = new System.Drawing.Size(760, 49); + this.groupBoxGeneralSettings.TabIndex = 12; + this.groupBoxGeneralSettings.TabStop = false; + this.groupBoxGeneralSettings.Text = "General Settings"; + // + // toolStripStatusLabel4 + // + this.toolStripStatusLabel4.Margin = new System.Windows.Forms.Padding(20, 3, 0, 2); + this.toolStripStatusLabel4.Name = "toolStripStatusLabel4"; + this.toolStripStatusLabel4.Size = new System.Drawing.Size(92, 17); + this.toolStripStatusLabel4.Text = "Frag Exceptions:"; + // + // FragDatListToolForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(784, 561); + this.Controls.Add(this.groupBoxGeneralSettings); + this.Controls.Add(this.groupBoxProcessFragDatListFile); + this.Controls.Add(this.label2); + this.Controls.Add(this.statusStrip1); + this.Controls.Add(this.groupBoxFragDatListFileBuilder); + this.Name = "FragDatListToolForm"; + this.Text = "Frag Dat List Tool"; + this.groupBoxFragDatListFileBuilder.ResumeLayout(false); + this.groupBoxFragDatListFileBuilder.PerformLayout(); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); + this.groupBoxProcessFragDatListFile.ResumeLayout(false); + this.groupBoxProcessFragDatListFile.PerformLayout(); + this.groupBoxGeneralSettings.ResumeLayout(false); + this.groupBoxGeneralSettings.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.GroupBox groupBoxFragDatListFileBuilder; + private System.Windows.Forms.Button btnChangeSearchPathRoot; + private System.Windows.Forms.Button btnStartBuild; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox txtSearchPathRoot; + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel2; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel3; + private System.Windows.Forms.Button btnStopBuild; + private System.Windows.Forms.Timer timer1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.GroupBox groupBoxProcessFragDatListFile; + private System.Windows.Forms.Button btnStopProcess; + private System.Windows.Forms.Button btnChangeFileToProcess; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox txtFileToProcess; + private System.Windows.Forms.Button btnStartProcess; + private System.Windows.Forms.Button btnChangeOutputFolder; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox txtOutputFolder; + private System.Windows.Forms.CheckBox chkCompressOutput; + private System.Windows.Forms.CheckBox chkIncludeFullPathAndFileName; + private System.Windows.Forms.GroupBox groupBoxGeneralSettings; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel4; + } +} \ No newline at end of file diff --git a/aclogview/FragDatListToolForm.cs b/aclogview/FragDatListToolForm.cs new file mode 100644 index 0000000..431efe9 --- /dev/null +++ b/aclogview/FragDatListToolForm.cs @@ -0,0 +1,548 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +using aclogview.Properties; + +namespace aclogview +{ + public partial class FragDatListToolForm : Form + { + public FragDatListToolForm() + { + InitializeComponent(); + } + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + + txtOutputFolder.Text = Settings.Default.FragDatFileOutputFolder; + txtSearchPathRoot.Text = Settings.Default.FindOpcodeInFilesRoot; + txtFileToProcess.Text = Settings.Default.FragDatFileToProcess; + + // Center to our owner, if we have one + if (Owner != null) + Location = new Point(Owner.Location.X + Owner.Width / 2 - Width / 2, Owner.Location.Y + Owner.Height / 2 - Height / 2); + } + + protected override void OnClosing(CancelEventArgs e) + { + searchAborted = true; + + Settings.Default.FragDatFileOutputFolder = txtOutputFolder.Text; + Settings.Default.FindOpcodeInFilesRoot = txtSearchPathRoot.Text; + Settings.Default.FragDatFileToProcess = txtFileToProcess.Text; + + base.OnClosing(e); + } + + private void btnChangeOutputFolder_Click(object sender, EventArgs e) + { + using (FolderBrowserDialog openFolder = new FolderBrowserDialog()) + { + if (openFolder.ShowDialog() == DialogResult.OK) + txtOutputFolder.Text = openFolder.SelectedPath; + } + } + + private void btnChangeSearchPathRoot_Click(object sender, EventArgs e) + { + using (FolderBrowserDialog openFolder = new FolderBrowserDialog()) + { + if (openFolder.ShowDialog() == DialogResult.OK) + txtSearchPathRoot.Text = openFolder.SelectedPath; + } + } + + private void btnChangeFileToProcess_Click(object sender, EventArgs e) + { + using (OpenFileDialog openFile = new OpenFileDialog()) + { + openFile.Filter = "Frag Dat List (*.frags)|*.frags"; + openFile.DefaultExt = ".frags"; + + if (openFile.ShowDialog() == DialogResult.OK) + txtFileToProcess.Text = openFile.FileName; + } + } + + + private readonly List filesToProcess = new List(); + private int filesProcessed; + private int fragmentsProcessed; + private int totalHits; + private int totalExceptions; + private bool searchAborted; + + private void ResetVariables() + { + filesToProcess.Clear(); + filesProcessed = 0; + fragmentsProcessed = 0; + totalHits = 0; + totalExceptions = 0; + searchAborted = false; + } + + + private void btnStartBuild_Click(object sender, EventArgs e) + { + if (!Directory.Exists(txtOutputFolder.Text)) + { + MessageBox.Show("Output folder does not exist.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + try + { + btnStartBuild.Enabled = false; + groupBoxGeneralSettings.Enabled = false; + groupBoxProcessFragDatListFile.Enabled = false; + + ResetVariables(); + + filesToProcess.AddRange(Directory.GetFiles(txtSearchPathRoot.Text, "*.pcap", SearchOption.AllDirectories)); + filesToProcess.AddRange(Directory.GetFiles(txtSearchPathRoot.Text, "*.pcapng", SearchOption.AllDirectories)); + + txtSearchPathRoot.Enabled = false; + btnChangeSearchPathRoot.Enabled = false; + chkCompressOutput.Enabled = false; + chkIncludeFullPathAndFileName.Enabled = false; + btnStopBuild.Enabled = true; + + timer1.Start(); + + new Thread(() => + { + // Do the actual work here + DoBuild(); + + if (!Disposing && !IsDisposed) + btnStopBuild.BeginInvoke((Action)(() => btnStopBuild_Click(null, null))); + }).Start(); + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + + btnStopBuild_Click(null, null); + } + } + + private void btnStopBuild_Click(object sender, EventArgs e) + { + searchAborted = true; + + timer1.Stop(); + + timer1_Tick(null, null); + + txtSearchPathRoot.Enabled = true; + btnChangeSearchPathRoot.Enabled = true; + chkCompressOutput.Enabled = true; + chkIncludeFullPathAndFileName.Enabled = true; + btnStartBuild.Enabled = true; + btnStopBuild.Enabled = false; + + groupBoxGeneralSettings.Enabled = true; + groupBoxProcessFragDatListFile.Enabled = true; + } + + + // ******************************************************************** + // *************************** Sample Files *************************** + // ******************************************************************** + private readonly FragDatListFile allFragDatFile = new FragDatListFile(); + private readonly FragDatListFile createObjectFragDatFile = new FragDatListFile(); + + private void DoBuild() + { + // ******************************************************************** + // ************************ Adjust These Paths ************************ + // ******************************************************************** + allFragDatFile.CreateFile(Path.Combine(txtOutputFolder.Text, "All.frags"), chkCompressOutput.Checked ? FragDatListFile.CompressionType.DeflateStream : FragDatListFile.CompressionType.None); + createObjectFragDatFile.CreateFile(Path.Combine(txtOutputFolder.Text, "CreateObject.frags"), chkCompressOutput.Checked ? FragDatListFile.CompressionType.DeflateStream : FragDatListFile.CompressionType.None); + + // Do not parallel this search + foreach (var currentFile in filesToProcess) + { + if (searchAborted || Disposing || IsDisposed) + break; + + try + { + ProcessFileForBuild(currentFile); + } + catch (Exception ex) + { + MessageBox.Show("File failed to process with exception: " + Environment.NewLine + ex, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + // ******************************************************************** + // ****************************** Cleanup ***************************** + // ******************************************************************** + allFragDatFile.CloseFile(); + createObjectFragDatFile.CloseFile(); + } + + private void ProcessFileForBuild(string fileName) + { + var records = PCapReader.LoadPcap(fileName, ref searchAborted); + + // Temperorary objects + var allFrags = new List(); + var createObjectFrags = new List(); + + foreach (var record in records) + { + if (searchAborted || Disposing || IsDisposed) + return; + + // ******************************************************************** + // ************************ Custom Search Code ************************ + // ******************************************************************** + foreach (BlobFrag frag in record.netPacket.fragList_) + { + try + { + if (frag.dat_.Length <= 4) + continue; + + Interlocked.Increment(ref fragmentsProcessed); + + FragDatListFile.PacketDirection packetDirection = (record.isSend ? FragDatListFile.PacketDirection.ClientToServer : FragDatListFile.PacketDirection.ServerToClient); + + // Write to emperorary object + allFrags.Add(new FragDatListFile.FragDatInfo(packetDirection, record.index, frag.dat_)); + + BinaryReader fragDataReader = new BinaryReader(new MemoryStream(frag.dat_)); + + var messageCode = fragDataReader.ReadUInt32(); + + // Write to emperorary object + if (messageCode == 0xF745) // Create Object + { + Interlocked.Increment(ref totalHits); + + createObjectFrags.Add(new FragDatListFile.FragDatInfo(packetDirection, record.index, frag.dat_)); + } + } + catch + { + // Do something with the exception maybe + Interlocked.Increment(ref totalExceptions); + } + } + } + + string outputFileName = (chkIncludeFullPathAndFileName.Checked ? fileName : (Path.GetFileName(fileName))); + + // ******************************************************************** + // ************************* Write The Output ************************* + // ******************************************************************** + allFragDatFile.Write(new KeyValuePair>(outputFileName, allFrags)); + createObjectFragDatFile.Write(new KeyValuePair>(outputFileName, createObjectFrags)); + + Interlocked.Increment(ref filesProcessed); + } + + + private void btnStartProcess_Click(object sender, EventArgs e) + { + try + { + btnStartProcess.Enabled = false; + groupBoxGeneralSettings.Enabled = false; + groupBoxFragDatListFileBuilder.Enabled = false; + + ResetVariables(); + + filesToProcess.Add(txtFileToProcess.Text); + + txtFileToProcess.Enabled = false; + btnChangeFileToProcess.Enabled = false; + btnStopProcess.Enabled = true; + + timer1.Start(); + + new Thread(() => + { + // Do the actual work here + DoProcess(); + + if (!Disposing && !IsDisposed) + btnStopProcess.BeginInvoke((Action)(() => btnStopProcess_Click(null, null))); + }).Start(); + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + + btnStopProcess_Click(null, null); + } + } + + private void btnStopProcess_Click(object sender, EventArgs e) + { + searchAborted = true; + + timer1.Stop(); + + timer1_Tick(null, null); + + txtFileToProcess.Enabled = true; + btnChangeFileToProcess.Enabled = true; + btnStartProcess.Enabled = true; + btnStopProcess.Enabled = false; + + groupBoxGeneralSettings.Enabled = true; + groupBoxFragDatListFileBuilder.Enabled = true; + } + + private void DoProcess() + { + // Do not parallel this search + foreach (var currentFile in filesToProcess) + { + if (searchAborted || Disposing || IsDisposed) + break; + + try + { + ProcessFileForExamination(currentFile); + } + catch (Exception ex) + { + MessageBox.Show("File failed to process with exception: " + Environment.NewLine + ex, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + + private void ProcessFileForExamination(string fileName) + { + var fragDatListFile = new FragDatListFile(); + + if (!fragDatListFile.OpenFile(fileName)) + return; + + var itemTypesToParse = new List(); + + var itemTypeKeys = new Dictionary>(); + var itemTypeStreamWriters = new Dictionary(); + + // If you only want to output a single item_type, you can change this code + foreach (ITEM_TYPE itemType in Enum.GetValues(typeof(ITEM_TYPE))) + { + itemTypesToParse.Add(itemType); + itemTypeKeys[itemType] = new List(); + itemTypeStreamWriters[itemType] = new StreamWriter(Path.Combine(txtOutputFolder.Text, itemType + ".csv.temp")); + } + + try + { + TreeView treeView = new TreeView(); + + while (true) + { + if (searchAborted || Disposing || IsDisposed) + return; + + KeyValuePair> kvp; + + if (!fragDatListFile.TryReadNext(out kvp)) + break; + + foreach (var frag in kvp.Value) + { + fragmentsProcessed++; + + try + { + // ******************************************************************** + // ********************** CUSTOM PROCESSING CODE ********************** + // ******************************************************************** + if (frag.Data.Length <= 4) + continue; + + BinaryReader fragDataReader = new BinaryReader(new MemoryStream(frag.Data)); + + var messageCode = fragDataReader.ReadUInt32(); + + if (messageCode == 0xF745) // Create Object + { + var parsed = CM_Physics.CreateObject.read(fragDataReader); + + if (!itemTypesToParse.Contains(parsed.wdesc._type)) + continue; + + totalHits++; + + // This bit of trickery uses the existing tree view parser code to create readable output, which we can then convert to csv + treeView.Nodes.Clear(); + parsed.contributeToTreeView(treeView); + if (treeView.Nodes.Count == 1) + { + var lineItems = new string[256]; + int lineItemCount = 0; + + ProcessNode(treeView.Nodes[0], itemTypeKeys[parsed.wdesc._type], null, lineItems, ref lineItemCount); + + var sb = new StringBuilder(); + + for (int i = 0; i < lineItemCount; i++) + { + if (i > 0) + sb.Append(','); + + var output = lineItems[i]; + + // Format the value for CSV output, if needed. + // We only do this for certain columns. This is very time consuming + if (output != null && itemTypeKeys[parsed.wdesc._type][i].EndsWith("name")) + { + if (output.Contains(",") || output.Contains("\"") || output.Contains("\r") || output.Contains("\n")) + { + var sb2 = new StringBuilder(); + sb2.Append("\""); + foreach (char nextChar in output) + { + sb2.Append(nextChar); + if (nextChar == '"') + sb2.Append("\""); + } + sb2.Append("\""); + output = sb2.ToString(); + } + + } + + if (output != null) + sb.Append(output); + } + + itemTypeStreamWriters[parsed.wdesc._type].WriteLine(sb.ToString()); + } + } + } + catch (EndOfStreamException) // This can happen when a frag is incomplete and we try to parse it + { + totalExceptions++; + } + } + } + } + finally + { + foreach (var streamWriter in itemTypeStreamWriters.Values) + streamWriter.Close(); + + fragDatListFile.CloseFile(); + + Interlocked.Increment(ref filesProcessed); + } + + // Read in the temp file and save it to a new file with the column headers + foreach (var kvp in itemTypeKeys) + { + if (kvp.Value.Count > 0) + { + using (var writer = new StreamWriter(Path.Combine(txtOutputFolder.Text, kvp.Key + ".csv"))) + { + var sb = new StringBuilder(); + + for (int i = 0; i < kvp.Value.Count; i++) + { + if (i > 0) + sb.Append(','); + + sb.Append(kvp.Value[i] ?? String.Empty); + } + + writer.WriteLine(sb.ToString()); + + using (var reader = new StreamReader(Path.Combine(txtOutputFolder.Text, kvp.Key + ".csv.temp"))) + { + string line; + while ((line = reader.ReadLine()) != null) + writer.WriteLine(line); + } + } + } + + File.Delete(Path.Combine(txtOutputFolder.Text, kvp.Key + ".csv.temp")); + } + } + + private void ProcessNode(TreeNode node, List keys, string prefix, string[] lineItems, ref int lineItemCount) + { + var kvp = ConvertNodeTextToKVP(node.Text); + + var nodeKey = (prefix == null ? kvp.Key : (prefix + "." + kvp.Key)); + + // ******************************************************************** + // ***************** YOU CAN OMIT CERTAIN NODES HERE ****************** + // ******************************************************************** + //if (nodeKey.StartsWith("physicsdesc.timestamps")) return; + + if (node.Nodes.Count == 0) + { + if (!keys.Contains(nodeKey)) + keys.Add(nodeKey); + + var keyIndex = keys.IndexOf(nodeKey); + + if (keyIndex >= lineItems.Length) + MessageBox.Show("Increase the lineItems array size"); + + lineItems[keyIndex] = kvp.Value; + + if (keyIndex + 1 > lineItemCount) + lineItemCount = keyIndex + 1; + } + else + { + foreach (TreeNode child in node.Nodes) + ProcessNode(child, keys, nodeKey, lineItems, ref lineItemCount); + } + } + + private static KeyValuePair ConvertNodeTextToKVP(string nodeText) + { + string key = null; + string value = null; + + var indexOfEquals = nodeText.IndexOf('='); + + if (indexOfEquals == -1) + value = nodeText; + else + { + key = nodeText.Substring(0, indexOfEquals).Trim(); + + if (nodeText.Length > indexOfEquals + 1) + value = nodeText.Substring(indexOfEquals + 1, nodeText.Length - indexOfEquals - 1).Trim(); + } + + return new KeyValuePair(key, value); + } + + + private void timer1_Tick(object sender, EventArgs e) + { + toolStripStatusLabel1.Text = "Files Processed: " + filesProcessed.ToString("N0") + " of " + filesToProcess.Count.ToString("N0"); + + toolStripStatusLabel2.Text = "Fragments Processed: " + fragmentsProcessed.ToString("N0"); + + toolStripStatusLabel3.Text = "Total Hits: " + totalHits.ToString("N0"); + + toolStripStatusLabel4.Text = "Frag Exceptions: " + totalExceptions.ToString("N0"); + } + } +} diff --git a/aclogview/FragDatListToolForm.resx b/aclogview/FragDatListToolForm.resx new file mode 100644 index 0000000..46cc79b --- /dev/null +++ b/aclogview/FragDatListToolForm.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 133, 17 + + \ No newline at end of file diff --git a/aclogview/Packets.cs b/aclogview/Packets.cs index f103ad7..496e31a 100644 --- a/aclogview/Packets.cs +++ b/aclogview/Packets.cs @@ -363,7 +363,7 @@ public static Position readOrigin(BinaryReader binaryReader) { } public void contributeToTreeNode(TreeNode node) { - node.Nodes.Add("objcell_id = " + objcell_id); + node.Nodes.Add("objcell_id = 0x" + objcell_id.ToString("X8")); TreeNode frameNode = node.Nodes.Add("frame = "); frame.contributeToTreeNode(frameNode); } diff --git a/aclogview/Properties/Settings.Designer.cs b/aclogview/Properties/Settings.Designer.cs index dc3b113..809f018 100644 --- a/aclogview/Properties/Settings.Designer.cs +++ b/aclogview/Properties/Settings.Designer.cs @@ -46,5 +46,29 @@ public int FindOpcodeInFilesOpcode { this["FindOpcodeInFilesOpcode"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string FragDatFileToProcess { + get { + return ((string)(this["FragDatFileToProcess"])); + } + set { + this["FragDatFileToProcess"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string FragDatFileOutputFolder { + get { + return ((string)(this["FragDatFileOutputFolder"])); + } + set { + this["FragDatFileOutputFolder"] = value; + } + } } } diff --git a/aclogview/Properties/Settings.settings b/aclogview/Properties/Settings.settings index b6fe278..5be3e1a 100644 --- a/aclogview/Properties/Settings.settings +++ b/aclogview/Properties/Settings.settings @@ -8,5 +8,11 @@ 0 + + + + + + \ No newline at end of file diff --git a/aclogview/aclogview.csproj b/aclogview/aclogview.csproj index 776dc0f..53b75de 100644 --- a/aclogview/aclogview.csproj +++ b/aclogview/aclogview.csproj @@ -108,6 +108,13 @@ Form1.cs + + + Form + + + FragDatListToolForm.cs + Form @@ -137,6 +144,9 @@ Form1.cs + + FragDatListToolForm.cs + ImagePopup.cs