--- xmlTools/trunk/posUpdate/XmlPatch.cs 2013/03/21 10:43:10 714 +++ xmlTools/trunk/posUpdate/XmlPatch.cs 2013/05/25 21:53:39 874 @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Text; using System.Xml; +using IronJS; namespace xmlTools { @@ -13,16 +15,20 @@ namespace xmlTools { String fileName; String forceFiles = ""; + bool globalNoBackups = false; + IronJS.Hosting.CSharp.Context jsEngine = null; // initialize only when necessary - public XmlPatch(String file) + public XmlPatch(String file, bool noBackups) { fileName = file; + globalNoBackups = noBackups; } - public XmlPatch(String file, String forceInFiles) + public XmlPatch(String file, String forceInFiles, bool noBackups) { fileName = file; forceFiles = forceInFiles; //We support apply the operation in diverse forced files (NameOfFile parameter will be ignored) + globalNoBackups = noBackups; } /// @@ -46,7 +52,7 @@ namespace xmlTools file.ReadLine(); //ignore start header while ((line = file.ReadLine()) != "") { - xmlToInject += line + "\n"; //get all the xml that will be injected + xmlToInject += line + System.Environment.NewLine; //get all the xml that will be injected } if (!addOperation(operation, xmlToInject)) { @@ -70,6 +76,22 @@ namespace xmlTools return false; } } + else if (line.StartsWith("@CUSTOMCODE ")) + { + string operation = line; + string jsCode = ""; + + file.ReadLine(); //ignore start header + while ((line = file.ReadLine()) != "") + { + jsCode += line + System.Environment.NewLine; //get all the xml that will be injected + } + if (!executeCode(operation, jsCode)) + { + Program.printAppError(Program.appErrors.PATCH_CODE_PROCESS_ERROR, "Error while performing code operation in patch file. Aborting..."); + return false; + } + } } file.Close(); @@ -87,23 +109,23 @@ namespace xmlTools { //@ADDTO File "example.xml" ParentElement "Animation" Element "Lookup" - string File = "", ParentElement = "", Element = ""; + string FileParam = "", ParentElementParam = "", ElementParam = ""; //---------------------------------------------------Parse Operation command (start) try { - if (forceFiles == null) + if (String.IsNullOrEmpty(forceFiles)) { - File = getPatchParameter(operation, "File"); + FileParam = getPatchParameter(operation, "File"); } else { - File = forceFiles; + FileParam = forceFiles; } - ParentElement = getPatchParameter(operation, "ParentElement"); //Get the ParentElement + ParentElementParam = getPatchParameter(operation, "ParentElement"); //Get the ParentElement - Element = getPatchParameter(operation, "Element"); //Get the Element + ElementParam = getPatchParameter(operation, "Element"); //Get the Element } catch (Exception e) { @@ -111,37 +133,39 @@ namespace xmlTools return false; } - if (Element == "") + if (String.IsNullOrEmpty(ElementParam)) { return false; } //---------------------------------------------------Parse Operation command (end) List filesToProcess = new List(); - if (File == "") + if (String.IsNullOrEmpty(FileParam)) { filesToProcess = Util.getAllXmlFiles(); //no file specified, use all xml files found in same folder } - else if (Util.containsWildcard(File)) + else if (Util.containsWildcard(FileParam)) { - filesToProcess = Util.getXmlFilesWildcard(File); + filesToProcess = Util.getXmlFilesWildcard(FileParam); } else { - filesToProcess.Add(File); + filesToProcess.Add(FileParam); } //---------------------------------------------------XML Injection (start) foreach (String currFile in filesToProcess) { - - Util.backupFile(currFile); + if (!this.globalNoBackups && !Util.ContainsIgnoreCase(operation, "NoBackups")) // only skip backup if specified via global parameter or in patch file + { + Util.backupFile(currFile); + } XmlDocument xdoc = new XmlDocument(); xdoc.Load(currFile); List myElements = new List(); - Util.getAllSpecificElements(xdoc.DocumentElement, ref myElements, Element, ParentElement); //Returns all after "Oni" element + Util.getAllSpecificElements(xdoc.DocumentElement, ref myElements, ElementParam, ParentElementParam); //Returns all after "Oni" element if (myElements.Count == 0) { @@ -177,23 +201,23 @@ namespace xmlTools { //@REMOVE File "example.xml" ParentElement "Particles" Element "Particle" - string File = "", ParentElement = "", Element = ""; + string FileParam = "", ParentElementParam = "", ElementParam = ""; //---------------------------------------------------Parse Operation command (start) try { - if (forceFiles == null) + if (String.IsNullOrEmpty(forceFiles)) { - File = getPatchParameter(operation, "File"); + FileParam = getPatchParameter(operation, "File"); } else { - File = forceFiles; + FileParam = forceFiles; } - ParentElement = getPatchParameter(operation, "ParentElement"); //Get the ParentElement + ParentElementParam = getPatchParameter(operation, "ParentElement"); //Get the ParentElement - Element = getPatchParameter(operation, "Element"); //Get the Element + ElementParam = getPatchParameter(operation, "Element"); //Get the Element } catch (Exception e) { @@ -201,7 +225,7 @@ namespace xmlTools return false; } - if (Element == "") + if (String.IsNullOrEmpty(ElementParam)) { return false; } @@ -209,17 +233,17 @@ namespace xmlTools //---------------------------------------------------Parse Operation command (end) List filesToProcess = new List(); - if (File == "") + if (String.IsNullOrEmpty(FileParam)) { filesToProcess = Util.getAllXmlFiles(); //no file specified, use all xml files found in same folder } - else if (Util.containsWildcard(File)) + else if (Util.containsWildcard(FileParam)) { - filesToProcess = Util.getXmlFilesWildcard(File); + filesToProcess = Util.getXmlFilesWildcard(FileParam); } else { - filesToProcess.Add(File); + filesToProcess.Add(FileParam); } //---------------------------------------------------XML Remove (start) @@ -227,13 +251,16 @@ namespace xmlTools foreach (String currFile in filesToProcess) { - Util.backupFile(currFile); + if (!this.globalNoBackups && !Util.ContainsIgnoreCase(operation, "NoBackups")) // only skip backup if specified via global parameter or in patch file + { + Util.backupFile(currFile); + } XmlDocument xdoc = new XmlDocument(); xdoc.Load(currFile); List myElements = new List(); - Util.getAllSpecificElements(xdoc.DocumentElement, ref myElements, Element, ParentElement); //Returns all after "Oni" element + Util.getAllSpecificElements(xdoc.DocumentElement, ref myElements, ElementParam, ParentElementParam); //Returns all after "Oni" element if (myElements.Count == 0) { @@ -253,7 +280,7 @@ namespace xmlTools } /// - /// + /// Executes a command for xmlTools /// /// /// true or false depending if succeed or not @@ -263,7 +290,7 @@ namespace xmlTools command = command.Replace("@COMMAND ", ""); //get only the command to process - if (command.Trim() == "") + if (String.IsNullOrEmpty(command.Trim())) { Program.printAppError(Program.appErrors.PATCH_COMMAND_NOT_FOUND, "Error parsing commandOperation in Patch file: Command is empty."); return false; @@ -271,32 +298,36 @@ namespace xmlTools try { - if (forceFiles != null) + if (!String.IsNullOrEmpty(forceFiles)) { string paramType = ""; // Filename already exists? - if (command.IndexOf("filename:") != -1) + if (Util.ContainsIgnoreCase(command, "filename:")) { paramType = "filename:"; } - else if (command.IndexOf("filename=") != -1) + else if (Util.ContainsIgnoreCase(command, "filename=")) { paramType = "filename="; } // Add the filename if it doesn't exists else { - command = command.Insert(command.Length-1," -filename:" + this.forceFiles); // -2 to be inside quotes + command = command.Insert(command.Length, " -filename:" + this.forceFiles); } - if (paramType != "") + if (!String.IsNullOrEmpty(paramType)) { int startIdx = command.IndexOf(paramType) + paramType.Length; int endIdx = command.IndexOf(" ", startIdx); // it may end with space if (endIdx == -1) { - endIdx = command.IndexOf("\"", startIdx); // or with quotes + endIdx = command.IndexOf("\n", startIdx); // or with endline + if (endIdx == -1) + { // Filename parameters is the last one in the file (file ends with this parameter) + endIdx = command.Length - 1; + } } string currFilename = command.Substring(startIdx, endIdx - startIdx); command = command.Replace(currFilename, this.forceFiles); @@ -304,34 +335,12 @@ namespace xmlTools } - command = command.Replace("\"", ""); // remove quotes - - ProcessStartInfo startInfo = new ProcessStartInfo(); - if (!Util.IsRunningOnMono()) + if (this.globalNoBackups && !Util.ContainsIgnoreCase(command, "nobackups")) // add noBackup flag if provided as global parameter { - startInfo.FileName = Util.getExeFileName(); - } - else{ - startInfo.FileName = "mono"; + command = command.Insert(command.Length, " -nobackups"); } - if (!Util.IsRunningOnMono()) - { - startInfo.Arguments = command; - } - else{ - startInfo.Arguments = Util.getExeFileName() + " " + command; - } - startInfo.UseShellExecute = false; // necessary to redirect output - startInfo.RedirectStandardOutput = true; - startInfo.RedirectStandardError = true; - startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; // hide new process window - Process p = System.Diagnostics.Process.Start(startInfo); - p.OutputDataReceived += commandStdOutputReceived; - p.ErrorDataReceived += commandStdErrorReceived; - p.BeginOutputReadLine(); - p.BeginErrorReadLine(); - p.WaitForExit(); + Program.Main(Util.stringToArgsArray(command)); // use the current process is more efficient than start a new one } catch (Exception e) { @@ -343,46 +352,107 @@ namespace xmlTools } /// - /// Reads asynchronously output from the new process where the command will be executed + /// Executes custom Javascript code over the xml file specified. Uses .NET JINT library. /// - /// - /// - private void commandStdOutputReceived(object sender, DataReceivedEventArgs e) + /// + /// + private bool executeCode(string operation, string jsCode) { + string FileParam = ""; - string myData = e.Data; - - if (myData != null) + //---------------------------------------------------Parse Operation command (start) + try { - if (myData.EndsWith("\n")) + if (String.IsNullOrEmpty(forceFiles)) { - Console.Write(myData); + FileParam = getPatchParameter(operation, "File"); } else { - Console.WriteLine(myData); + FileParam = forceFiles; } + + } + catch (Exception e) + { + Program.printAppError(Program.appErrors.PATCH_CODE_PROCESS_ERROR, "Error parsing codeOperation in Patch file.\n" + e.ToString()); + return false; } - } + //---------------------------------------------------Parse Operation command (end) + List filesToProcess = new List(); + if (String.IsNullOrEmpty(FileParam)) + { + filesToProcess = Util.getAllXmlFiles(); //no file specified, use all xml files found in same folder + } + else if (Util.containsWildcard(FileParam)) + { + filesToProcess = Util.getXmlFilesWildcard(FileParam); + } + else + { + filesToProcess.Add(FileParam); + } - private void commandStdErrorReceived(object sender, DataReceivedEventArgs e) - { + //---------------------------------------------------JS Code Proccess (start) + foreach (String currXMLFile in filesToProcess) + { + if (!this.globalNoBackups && !Util.ContainsIgnoreCase(operation, "NoBackups")) // only skip backup if specified via global parameter or in patch file + { + Util.backupFile(currXMLFile); + } - string myData = e.Data; + string xmlFileContent = File.ReadAllText(currXMLFile); - if (myData != null) - { - if (myData.EndsWith("\n")) + // Initialize Jint Engine + if (jsEngine == null) { - Console.Error.Write(myData); + jsEngine = new IronJS.Hosting.CSharp.Context(); + + // Load XML libraries + jsEngine.Execute(xmlTools.Properties.Resources.tinyxmlsax); + jsEngine.Execute(xmlTools.Properties.Resources.tinyxmlw3cdom); } - else + + // Construct code to execute + StringBuilder sourceCode = new StringBuilder(); + + // give user the xml we needs to edit... + sourceCode.Append("var $xmlData='").Append(xmlFileContent.Replace(System.Environment.NewLine, " \\" + System.Environment.NewLine)).Append("';").AppendLine(); // replace is for multine string in javascript (http://stackoverflow.com/questions/805107/creating-multiline-strings-in-javascript) + // append the user js code... + sourceCode.Append(jsCode).AppendLine(); + // return to .NET the new xml data + sourceCode.Append("$xmlData;"); + + try + { + xmlFileContent = jsEngine.Execute(sourceCode.ToString()).ToString(); + } + catch (Exception e) + { + Program.printAppError(Program.appErrors.PATCH_CODE_PROCESS_ERROR, "Error parsing code in customCodeOperation in Patch file.\n" + e.ToString()); + return false; + } + + // Let's see if the returned result is valid xml... + try + { + XmlDocument xmlDoc = new XmlDocument(); + + xmlDoc.LoadXml(xmlFileContent); + + xmlDoc.Save(currXMLFile); //saving the new xml with this method will auto ident it. + + } + catch (Exception e) { - Console.Error.WriteLine(myData); + Program.printAppError(Program.appErrors.PATCH_CODE_PARSE_XML_OUTPUT_ERROR, "Error parsing result xml to customCodeOperation in Patch file.\n" + e.ToString()); + return false; } } + //---------------------------------------------------JS Code Proccess (end) + return true; } private string getPatchParameter(string line, string parameterName)