From 2748647eb358c850baf27e50bf218071e0d23745 Mon Sep 17 00:00:00 2001 From: cuqmbr Date: Wed, 17 Aug 2022 12:56:12 +0300 Subject: [PATCH] feat: add concatenation option The option makes possible to concatenate multiple kml files generated by the program --- netxml2kml/Methods/CliOptionsHandlers.cs | 61 +++++++++++++++++++-- netxml2kml/Program.cs | 70 +++++++++++++++++++++--- netxml2kml/netxml2kml.csproj | 7 +++ 3 files changed, 125 insertions(+), 13 deletions(-) diff --git a/netxml2kml/Methods/CliOptionsHandlers.cs b/netxml2kml/Methods/CliOptionsHandlers.cs index 9baec16..af1a37a 100644 --- a/netxml2kml/Methods/CliOptionsHandlers.cs +++ b/netxml2kml/Methods/CliOptionsHandlers.cs @@ -8,7 +8,8 @@ namespace netxml2kml.Methods; public static class CliOptionsHandlers { public static void UniversalHandler(FileInfo? inputFile, - FileInfo? outputFile, bool useDatabase, string? sqlQuery) + FileInfo? outputFile, bool useDatabase, string? sqlQuery, + IEnumerable? concatFiles) { // Run some logic based on options combination if (inputFile != null && outputFile != null) @@ -25,7 +26,8 @@ public static class CliOptionsHandlers FilterWirelessNetworksInMemory(ref wirelessNetworks, sqlQuery); } - var kmlString = GetKmlString(wirelessNetworks); + var kmlString = GetKmlString(wirelessNetworks, + $"WiFi Map - {outputFile.Name}"); Helpers.WriteStringToFile(kmlString, outputFile); } else if (inputFile != null && outputFile == null && useDatabase) @@ -45,11 +47,15 @@ public static class CliOptionsHandlers if (sqlQuery != null) { - kmlString = GetKmlString(FilterWirelessNetworksFromDatabase(sqlQuery)); + kmlString = GetKmlString( + FilterWirelessNetworksFromDatabase(sqlQuery), + $"WiFi Map - {outputFile.Name}"); } else { - kmlString = GetKmlString(FilterWirelessNetworksFromDatabase("SELECT * FROM WirelessNetworks")); + kmlString = GetKmlString( + FilterWirelessNetworksFromDatabase("SELECT * FROM WirelessNetworks"), + $"WiFi Map - {outputFile.Name}"); } Helpers.WriteStringToFile(kmlString, outputFile); @@ -60,6 +66,12 @@ public static class CliOptionsHandlers using var dbContext = new DatabaseContext(); Console.WriteLine(dbContext.Database.ExecuteSqlRaw(sqlQuery)); } + else if (concatFiles != null && outputFile != null) + { + var inputFiles = concatFiles as FileInfo[] ?? concatFiles.ToArray(); + var kmlString = ConcatKml(inputFiles); + Helpers.WriteStringToFile(kmlString, outputFile); + } else { Console.WriteLine("Options combination is unsupported or some option lacks an argument." + @@ -129,6 +141,7 @@ public static class CliOptionsHandlers document.Add(wpaFolder); document.Add(wepFolder); document.Add(opnFolder); + document.Add(unknownFolder); kml.Add(document); kmlTree.Add(kml); @@ -282,4 +295,44 @@ public static class CliOptionsHandlers using var dbContext = new DatabaseContext(); return dbContext.WirelessNetworks.FromSqlRaw(sqlQuery).ToArray(); } + + private static string ConcatKml(IEnumerable inputFiles) + { + var inFs = inputFiles.ToArray(); + var result = XDocument.Load(inFs[0].FullName); + + result.Root!.Element("Document")!.Element("name")!.Value = + "WiFi Map - Concatenated"; + + var folders = result.Root?.Element("Document")?.Elements("Folder") + .ToArray(); + var wpa3Folder = folders?[0]; + var wpa2Folder = folders?[1]; + var wpaFolder = folders?[2]; + var wepFolder = folders?[3]; + var opnFolder = folders?[4]; + var unknownFolder = folders?[5]; + + foreach (var inF in inFs[1..]) + { + var inFDoc = XDocument.Load(inF.FullName); + var inFolders = inFDoc.Root?.Element("Document")?.Elements("Folder") + .ToArray(); + + inFolders?[0].Elements("Placemark").ToList() + .ForEach(p => wpa3Folder?.Add(p)); + inFolders?[1].Elements("Placemark").ToList() + .ForEach(p => wpa2Folder?.Add(p)); + inFolders?[2].Elements("Placemark").ToList() + .ForEach(p => wpaFolder?.Add(p)); + inFolders?[3].Elements("Placemark").ToList() + .ForEach(p => wepFolder?.Add(p)); + inFolders?[4].Elements("Placemark").ToList() + .ForEach(p => opnFolder?.Add(p)); + inFolders?[5].Elements("Placemark").ToList() + .ForEach(p => unknownFolder?.Add(p)); + } + + return result.ToString(); + } } \ No newline at end of file diff --git a/netxml2kml/Program.cs b/netxml2kml/Program.cs index 631bd58..72be7fc 100644 --- a/netxml2kml/Program.cs +++ b/netxml2kml/Program.cs @@ -1,4 +1,5 @@ using System.CommandLine; +using System.Xml.Linq; using netxml2kml.Methods; namespace netxml2kml; @@ -7,8 +8,8 @@ class Program { static int Main(string[] args) { - // Define CLI parser options, commands & handlers - + /*-------------------------Input Option----------------------------*/ + var inputOption = new Option( aliases: new[] {"-i", "--input"}, description: "Path to the file to be converted.") @@ -22,8 +23,7 @@ class Program if (inputFile == null) { - result.ErrorMessage = - "Argument for input option is not specified."; + result.ErrorMessage = "Argument for input option is not specified."; return; } @@ -34,6 +34,8 @@ class Program } }); + /*-------------------------Output Option---------------------------*/ + var outputOption = new Option( aliases: new[] {"-o", "--output"}, description: "The name of the file to be created.", @@ -85,8 +87,7 @@ class Program if (outputFile == null) { - result.ErrorMessage = - "Argument for output option is not specified."; + result.ErrorMessage = "Argument for output option is not specified."; return; } @@ -97,30 +98,81 @@ class Program } }); + /*-------------------------Concat Option---------------------------*/ + + var concatOption = new Option?>( + aliases: new[] {"-c", "--concat"}, + description: "Concatenate multiple kml files. ") + { + Arity = ArgumentArity.OneOrMore, + AllowMultipleArgumentsPerToken = true + }; + + concatOption.AddValidator(result => + { + var inputFiles = result.GetValueForOption(concatOption); + + if (inputFiles == null) + { + result.ErrorMessage = "Argument for concat option is not specified."; + return; + } + + var fileInfos = inputFiles as FileInfo[] ?? inputFiles.ToArray(); + + foreach (var inputFile in fileInfos) + { + if (!inputFile.Exists) + { + result.ErrorMessage = $"File {inputFile.FullName} doesen't exist."; + return; + } + } + + // Validate that inputted files have the same format + if (fileInfos.Any(fi => XDocument.Load(fi.FullName).Root?.Name != "kml")) + { + result.ErrorMessage = "Some files passed to concat option have invalid content."; + return; + } + }); + + /*------------------------Database Option--------------------------*/ + var databaseOption = new Option( aliases: new[] {"-d", "--use-database"}, description: - "Use database. Save/retrieve wireless networks and clients to/from sqlite database.") + "Use database (save/retrieve data from database).") { Arity = ArgumentArity.ZeroOrOne }; + /*------------------------Query Option-----------------------------*/ + var queryOption = new Option( aliases: new[] {"-q", "--query"}, - description: "Filter input using sql query.") + description: "Filter input/output using sql query.") { Arity = ArgumentArity.ZeroOrOne }; + /*----------------------Root Command Setup-------------------------*/ + var rootCommand = new RootCommand("netxml2kml – .netxml to .kml converter."); rootCommand.AddOption(inputOption); rootCommand.AddOption(outputOption); rootCommand.AddOption(databaseOption); rootCommand.AddOption(queryOption); + rootCommand.AddOption(concatOption); + /*----------------------Handlers Setup-----------------------------*/ + rootCommand.SetHandler(CliOptionsHandlers.UniversalHandler, - inputOption, outputOption, databaseOption, queryOption); + inputOption, outputOption, databaseOption, queryOption, + concatOption); + + /*----------------------------------------------------------------*/ return rootCommand.Invoke(args); } diff --git a/netxml2kml/netxml2kml.csproj b/netxml2kml/netxml2kml.csproj index 46bbb5c..79207c9 100644 --- a/netxml2kml/netxml2kml.csproj +++ b/netxml2kml/netxml2kml.csproj @@ -5,6 +5,13 @@ net6.0 enable enable + netxml2kml + cuqmbr + netxml to kml CLI converter & tools + cuqmbr + en-US + 1.0.0 + 1.0.0