using System; using System.IO; using System.Linq; using GeViSetEditor.Core.Parsers; using GeViSetEditor.Core.Models; namespace GeViSetEditor.CLI.Commands { /// /// Test modification capabilities: edit/add/delete configuration nodes /// public static class ModifyConfigCommand { public static void Execute(string inputPath, string outputPath = null) { if (!File.Exists(inputPath)) { Console.WriteLine($"ERROR: File not found: {inputPath}"); return; } try { Console.WriteLine("=== Configuration Modification Test ===\n"); // Read and parse original file byte[] originalData = File.ReadAllBytes(inputPath); Console.WriteLine($"Input: {inputPath}"); Console.WriteLine($"Original size: {originalData.Length:N0} bytes\n"); var parser = new ComprehensiveConfigParser(); var config = parser.Parse(originalData); Console.WriteLine($"Parsed {config.Statistics.TotalNodes:N0} nodes\n"); // Show original state Console.WriteLine("=== Original Configuration (sample) ==="); ShowSampleNodes(config); // Perform modifications Console.WriteLine("\n=== Applying Modifications ==="); int modificationsCount = 0; // 1. Modify some booleans var booleans = config.RootNodes.Where(n => n.NodeType == "boolean").Take(3).ToList(); foreach (var node in booleans) { bool oldValue = (bool)node.Value; node.Value = !oldValue; Console.WriteLine($"Modified boolean at offset {node.StartOffset}: {oldValue} → {node.Value}"); modificationsCount++; } // 2. Modify some integers var integers = config.RootNodes.Where(n => n.NodeType == "integer").Take(3).ToList(); foreach (var node in integers) { int oldValue = (int)node.Value; node.Value = oldValue + 1000; Console.WriteLine($"Modified integer at offset {node.StartOffset}: {oldValue} → {node.Value}"); modificationsCount++; } // 3. Modify some strings var strings = config.RootNodes.Where(n => n.NodeType == "string" && !string.IsNullOrEmpty(n.Value?.ToString())).Take(2).ToList(); foreach (var node in strings) { string oldValue = node.Value?.ToString() ?? ""; node.Value = oldValue + "_MODIFIED"; Console.WriteLine($"Modified string at offset {node.StartOffset}: '{oldValue}' → '{node.Value}'"); modificationsCount++; } // 4. Add a new property var newProperty = new ConfigNode { NodeType = "property", Name = "TestProperty", Value = 12345, ValueType = "integer" }; config.RootNodes.Add(newProperty); Console.WriteLine($"Added new property: {newProperty.Name} = {newProperty.Value}"); modificationsCount++; Console.WriteLine($"\nTotal modifications: {modificationsCount}"); // Apply modifications in-place (preserves binary structure) Console.WriteLine("\n=== Applying In-Place Modifications ==="); byte[] modifiedData = config.GetDataForWriting(); // Get copy of original data var inPlaceModifier = new InPlaceConfigModifier(); int appliedCount = 0; // Apply boolean modifications foreach (var node in booleans) { if (inPlaceModifier.ModifyNode(modifiedData, node, node.Value)) { Console.WriteLine($"✓ Applied boolean modification at offset {node.StartOffset}"); appliedCount++; } } // Apply integer modifications foreach (var node in integers) { if (inPlaceModifier.ModifyNode(modifiedData, node, node.Value)) { Console.WriteLine($"✓ Applied integer modification at offset {node.StartOffset}"); appliedCount++; } } // Apply string modifications foreach (var node in strings) { if (inPlaceModifier.ModifyNode(modifiedData, node, node.Value)) { Console.WriteLine($"✓ Applied string modification at offset {node.StartOffset}"); appliedCount++; } } Console.WriteLine($"\n{appliedCount} out of {modificationsCount - 1} in-place modifications applied"); Console.WriteLine($"(Note: New property addition not supported in in-place mode)"); Console.WriteLine($"\nModified size: {modifiedData.Length:N0} bytes"); Console.WriteLine($"Size difference: {modifiedData.Length - originalData.Length:+#;-#;0} bytes (should be 0 for in-place)"); // Save to output file string outputFilePath = outputPath ?? Path.Combine( Path.GetDirectoryName(inputPath), Path.GetFileNameWithoutExtension(inputPath) + "_modified" + Path.GetExtension(inputPath) ); File.WriteAllBytes(outputFilePath, modifiedData); Console.WriteLine($"Saved to: {outputFilePath}"); // Verify by parsing the modified file Console.WriteLine("\n=== Verifying Modified File ==="); var verifyConfig = parser.Parse(modifiedData); Console.WriteLine($"Parsed {verifyConfig.Statistics.TotalNodes:N0} nodes from modified file"); // Check if modifications persisted Console.WriteLine("\n=== Verification Results ==="); int verifiedChanges = 0; int expectedChanges = appliedCount; // Only verify what was actually applied // Check modified booleans foreach (var originalNode in booleans) { var modifiedNode = verifyConfig.RootNodes.FirstOrDefault(n => n.NodeType == "boolean" && n.StartOffset == originalNode.StartOffset); if (modifiedNode != null && modifiedNode.Value.Equals(originalNode.Value)) { Console.WriteLine($"✓ Boolean at {originalNode.StartOffset}: expected={originalNode.Value}, actual={modifiedNode.Value}"); verifiedChanges++; } else { Console.WriteLine($"✗ Boolean at {originalNode.StartOffset}: expected={originalNode.Value}, actual={modifiedNode?.Value?.ToString() ?? "NOT FOUND"}"); } } // Check modified integers foreach (var originalNode in integers) { var modifiedNode = verifyConfig.RootNodes.FirstOrDefault(n => n.NodeType == "integer" && n.StartOffset == originalNode.StartOffset); if (modifiedNode != null && modifiedNode.Value.Equals(originalNode.Value)) { Console.WriteLine($"✓ Integer at {originalNode.StartOffset}: expected={originalNode.Value}, actual={modifiedNode.Value}"); verifiedChanges++; } else { Console.WriteLine($"✗ Integer at {originalNode.StartOffset}: expected={originalNode.Value}, actual={modifiedNode?.Value?.ToString() ?? "NOT FOUND"}"); } } // Check modified strings foreach (var originalNode in strings) { var modifiedNode = verifyConfig.RootNodes.FirstOrDefault(n => n.NodeType == "string" && n.StartOffset == originalNode.StartOffset); if (modifiedNode != null && modifiedNode.Value?.ToString() == originalNode.Value?.ToString()) { string displayValue = originalNode.Value?.ToString() ?? ""; if (displayValue.Length > 30) displayValue = displayValue.Substring(0, 27) + "..."; Console.WriteLine($"✓ String at {originalNode.StartOffset}: '{displayValue}'"); verifiedChanges++; } else { Console.WriteLine($"✗ String at {originalNode.StartOffset}: VERIFICATION FAILED"); } } Console.WriteLine($"\n{verifiedChanges}/{expectedChanges} modifications verified successfully!"); if (verifiedChanges == expectedChanges) { Console.WriteLine("\n✓ All in-place modifications applied and verified successfully!"); Console.WriteLine($"Modified file saved to: {outputFilePath}"); Console.WriteLine($"\nFile size preserved: {modifiedData.Length:N0} bytes (in-place modification)"); } else { Console.WriteLine($"\n⚠ Some modifications could not be verified! ({verifiedChanges}/{expectedChanges})"); } } catch (Exception ex) { Console.WriteLine($"\n✗ ERROR: {ex.Message}"); Console.WriteLine($"Stack trace:\n{ex.StackTrace}"); } } private static void ShowSampleNodes(ComprehensiveConfigFile config) { Console.WriteLine("First 5 booleans:"); foreach (var node in config.RootNodes.Where(n => n.NodeType == "boolean").Take(5)) { Console.WriteLine($" Offset {node.StartOffset}: {node.Value}"); } Console.WriteLine("\nFirst 5 integers:"); foreach (var node in config.RootNodes.Where(n => n.NodeType == "integer").Take(5)) { Console.WriteLine($" Offset {node.StartOffset}: {node.Value}"); } Console.WriteLine("\nFirst 5 strings:"); foreach (var node in config.RootNodes.Where(n => n.NodeType == "string").Take(5)) { string value = node.Value?.ToString() ?? "null"; if (value.Length > 40) value = value.Substring(0, 37) + "..."; Console.WriteLine($" Offset {node.StartOffset}: '{value}'"); } } } }