source: xmlTools/trunk/posUpdate/XmlPatch.cs@ 726

Last change on this file since 726 was 710, checked in by s10k, 12 years ago
File size: 14.7 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.Text;
5using System.Xml;
6
7namespace xmlTools
8{
9 /// <summary>
10 /// This classes parses a .patch xml tools file and applies its content to the files which it specifies
11 /// </summary>
12 class XmlPatch
13 {
14 String fileName;
15 String forceFiles = "";
16
17 public XmlPatch(String file)
18 {
19 fileName = file;
20 }
21
22 public XmlPatch(String file, String forceInFiles)
23 {
24 fileName = file;
25 forceFiles = forceInFiles; //We support apply the operation in diverse forced files (NameOfFile parameter will be ignored)
26 }
27
28 /// <summary>
29 /// Applies the patch file. Returns true if successful otherwise returns false.
30 /// </summary>
31 /// <returns></returns>
32 public bool startPatch()
33 {
34 string line;
35
36 // Read the file and display it line by line.
37 System.IO.StreamReader file = new System.IO.StreamReader(fileName);
38
39 while ((line = file.ReadLine()) != null) //read while we don't reach the end of the file
40 {
41 if (line.StartsWith("@ADDTO "))
42 {
43 string operation = line;
44 string xmlToInject = "";
45
46 file.ReadLine(); //ignore <xml> start header
47 while ((line = file.ReadLine()) != "</xml>")
48 {
49 xmlToInject += line + "\n"; //get all the xml that will be injected
50 }
51 if (!addOperation(operation, xmlToInject))
52 {
53 Program.printAppError(Program.appErrors.PATCH_ADDTO_PROCESS_ERROR, "Error while performing adding operation in patch file. Aborting...");
54 return false;
55 }
56 }
57 else if (line.StartsWith("@REMOVE "))
58 {
59 if (!removeOperation(line))
60 {
61 Program.printAppError(Program.appErrors.PATCH_REMOVE_PROCESS_ERROR, "Error while performing remove operation in patch file. Aborting...");
62 return false;
63 }
64 }
65 else if (line.StartsWith("@COMMAND "))
66 {
67 if (!executeCommand(line))
68 {
69 Program.printAppError(Program.appErrors.PATCH_COMMAND_PROCESS_ERROR, "Error while performing command operation in patch file. Aborting...");
70 return false;
71 }
72 }
73 }
74
75 file.Close();
76
77 return true;
78 }
79
80 /// <summary>
81 /// Inserts xml in a desired Element. Returns true or false if it succeeds
82 /// </summary>
83 /// <param name="operation"></param>
84 /// <param name="xmlToInject"></param>
85 /// <returns></returns>
86 private bool addOperation(string operation, string xmlToInject)
87 {
88 //@ADDTO File "example.xml" ParentElement "Animation" Element "Lookup"
89
90 string File = "", ParentElement = "", Element = "";
91
92 //---------------------------------------------------Parse Operation command (start)
93 try
94 {
95 if (forceFiles == null)
96 {
97 File = getPatchParameter(operation, "File");
98 }
99 else
100 {
101 File = forceFiles;
102 }
103
104 ParentElement = getPatchParameter(operation, "ParentElement"); //Get the ParentElement
105
106 Element = getPatchParameter(operation, "Element"); //Get the Element
107 }
108 catch (Exception e)
109 {
110 Program.printAppError(Program.appErrors.PATCH_ADDTO_ERROR_PARSING_XML, "Error parsing addOperation in Patch file.\n" + e.ToString());
111 return false;
112 }
113
114 if (Element == "")
115 {
116 return false;
117 }
118
119 //---------------------------------------------------Parse Operation command (end)
120 List<String> filesToProcess = new List<String>();
121 if (File == "")
122 {
123 filesToProcess = Util.getAllXmlFiles(); //no file specified, use all xml files found in same folder
124 }
125 else if (Util.containsWildcard(File))
126 {
127 filesToProcess = Util.getXmlFilesWildcard(File);
128 }
129 else
130 {
131 filesToProcess.Add(File);
132 }
133
134 //---------------------------------------------------XML Injection (start)
135 foreach (String currFile in filesToProcess)
136 {
137
138 Util.backupFile(currFile);
139
140 XmlDocument xdoc = new XmlDocument();
141 xdoc.Load(currFile);
142
143 List<XmlNode> myElements = new List<XmlNode>();
144 Util.getAllSpecificElements(xdoc.DocumentElement, ref myElements, Element, ParentElement); //Returns all after "Oni" element
145
146 if (myElements.Count == 0)
147 {
148 Program.printAppError(Program.appErrors.PATCH_ELEMENT_NOT_FOUND, "Error in addOperation in Patch file: the element specified doesn't exist.");
149 return false;
150 }
151
152 try
153 {
154 XmlNode newXml = xdoc.ImportNode(Util.stringToXmlNode(xmlToInject), true); //necessary to import node or ArgumentException will be thrown when appending
155
156 myElements[myElements.Count - 1].AppendChild(newXml); // Append the code after last element
157
158 xdoc.Save(currFile);
159 }
160 catch (XmlException e)
161 {
162 Program.printAppError(Program.appErrors.PATCH_ADDTO_ERROR_PARSING_XML, "Error parsing xml to addOperation in Patch file.\n" + e.ToString());
163 return false;
164 }
165 }
166 //---------------------------------------------------XML Injection (end)
167
168 return true;
169 }
170
171 /// <summary>
172 /// Removes a xml element, right now it removes the first element it finds with matchs "Element" and "ParentElement" parameters
173 /// </summary>
174 /// <param name="operation"></param>
175 /// <returns>true or false depending if succeed or not</returns>
176 private bool removeOperation(string operation)
177 {
178 //@REMOVE File "example.xml" ParentElement "Particles" Element "Particle"
179
180 string File = "", ParentElement = "", Element = "";
181
182 //---------------------------------------------------Parse Operation command (start)
183 try
184 {
185 if (forceFiles == null)
186 {
187 File = getPatchParameter(operation, "File");
188 }
189 else
190 {
191 File = forceFiles;
192 }
193
194 ParentElement = getPatchParameter(operation, "ParentElement"); //Get the ParentElement
195
196 Element = getPatchParameter(operation, "Element"); //Get the Element
197 }
198 catch (Exception e)
199 {
200 Program.printAppError(Program.appErrors.PATCH_REMOVE_PROCESS_ERROR, "Error parsing removeOperation in Patch file.\n" + e.ToString());
201 return false;
202 }
203
204 if (Element == "")
205 {
206 return false;
207 }
208
209 //---------------------------------------------------Parse Operation command (end)
210
211 List<String> filesToProcess = new List<String>();
212 if (File == "")
213 {
214 filesToProcess = Util.getAllXmlFiles(); //no file specified, use all xml files found in same folder
215 }
216 else if (Util.containsWildcard(File))
217 {
218 filesToProcess = Util.getXmlFilesWildcard(File);
219 }
220 else
221 {
222 filesToProcess.Add(File);
223 }
224
225 //---------------------------------------------------XML Remove (start)
226
227 foreach (String currFile in filesToProcess)
228 {
229
230 Util.backupFile(currFile);
231
232 XmlDocument xdoc = new XmlDocument();
233 xdoc.Load(currFile);
234
235 List<XmlNode> myElements = new List<XmlNode>();
236 Util.getAllSpecificElements(xdoc.DocumentElement, ref myElements, Element, ParentElement); //Returns all after "Oni" element
237
238 if (myElements.Count == 0)
239 {
240 Program.printAppError(Program.appErrors.PATCH_ELEMENT_NOT_FOUND, "Error in removeOperation in Patch file: the element specified doesn't exist.");
241 return false;
242 }
243
244 myElements[0].ParentNode.RemoveChild(myElements[0]); // Removes the first occurrence which matches the "Element" and "ParentElement" given
245
246 xdoc.Save(currFile);
247
248 }
249 //---------------------------------------------------XML Remove (end)
250
251
252 return true;
253 }
254
255 /// <summary>
256 ///
257 /// </summary>
258 /// <param name="command"></param>
259 /// <returns>true or false depending if succeed or not</returns>
260 private bool executeCommand(string command)
261 {
262 //---------------------------------------------------Parse Operation command (start)
263
264 command = command.Replace("@COMMAND ", ""); //get only the command to process
265
266 if (command.Trim() == "")
267 {
268 Program.printAppError(Program.appErrors.PATCH_COMMAND_NOT_FOUND, "Error parsing commandOperation in Patch file: Command is empty.");
269 return false;
270 }
271
272 try
273 {
274 if (forceFiles != null)
275 {
276 string paramType = "";
277
278 // Filename already exists?
279 if (command.IndexOf("filename:") != -1)
280 {
281 paramType = "filename:";
282 }
283 else if (command.IndexOf("filename=") != -1)
284 {
285 paramType = "filename=";
286 }
287 // Add the filename if it doesn't exists
288 else
289 {
290 command = command.Insert(command.Length-1," -filename:" + this.forceFiles); // -2 to be inside quotes
291 }
292
293 if (paramType != "")
294 {
295 int startIdx = command.IndexOf(paramType) + paramType.Length;
296 int endIdx = command.IndexOf(" ", startIdx); // it may end with space
297 if (endIdx == -1)
298 {
299 endIdx = command.IndexOf("\"", startIdx); // or with quotes
300 }
301 string currFilename = command.Substring(startIdx, endIdx - startIdx);
302 command = command.Replace(currFilename, this.forceFiles);
303 }
304
305 }
306
307 command = command.Replace("\"", ""); // remove quotes
308
309 ProcessStartInfo startInfo = new ProcessStartInfo();
310 if (!Util.IsRunningOnMono())
311 {
312 startInfo.FileName = Util.getExeFileName();
313 }
314 else{
315 startInfo.FileName = "mono";
316 }
317 if (!Util.IsRunningOnMono())
318 {
319 startInfo.Arguments = command;
320 }
321 else{
322 startInfo.Arguments = Util.getExeFileName() + " " + command;
323 }
324 startInfo.UseShellExecute = false; // necessary to redirect output
325 startInfo.RedirectStandardOutput = true;
326 startInfo.RedirectStandardError = true;
327 startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; // hide new process window
328
329 Process p = System.Diagnostics.Process.Start(startInfo);
330 p.OutputDataReceived += commandStdOutputReceived;
331 p.ErrorDataReceived += commandStdErrorReceived;
332 p.BeginOutputReadLine();
333 p.BeginErrorReadLine();
334 p.WaitForExit();
335 }
336 catch (Exception e)
337 {
338 Program.printAppError(Program.appErrors.PATCH_COMMAND_PROCESS_ERROR, "Error processing command in Patch file.\n" + e.ToString());
339 return false;
340 }
341
342 return true;
343 }
344
345 /// <summary>
346 /// Reads asynchronously output from the new process where the command will be executed
347 /// </summary>
348 /// <param name="sender"></param>
349 /// <param name="e"></param>
350 private void commandStdOutputReceived(object sender, DataReceivedEventArgs e)
351 {
352
353 string myData = e.Data;
354
355 if (myData != null)
356 {
357 if (myData.EndsWith("\n"))
358 {
359 Console.Write(myData);
360 }
361 else
362 {
363 Console.WriteLine(myData);
364 }
365 }
366
367 }
368
369 private void commandStdErrorReceived(object sender, DataReceivedEventArgs e)
370 {
371
372 string myData = e.Data;
373
374 if (myData != null)
375 {
376 if (myData.EndsWith("\n"))
377 {
378 Console.Error.Write(myData);
379 }
380 else
381 {
382 Console.Error.WriteLine(myData);
383 }
384 }
385
386 }
387
388 private string getPatchParameter(string line, string parameterName)
389 {
390 string result = "";
391 int startIdx = 0, endIdx = 0;
392
393 string temp = parameterName + " \"";
394
395 startIdx = line.IndexOf(temp);
396 if (startIdx != -1) //we have Parameter specified
397 {
398 startIdx += temp.Length;
399 endIdx = line.IndexOf("\"", startIdx);
400 result = line.Substring(startIdx, endIdx - startIdx); //Get the parameter value
401 }
402
403 return result;
404 }
405 }
406}
Note: See TracBrowser for help on using the repository browser.