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

Last change on this file since 742 was 742, checked in by s10k, 12 years ago

0.8

File size: 13.4 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 bool globalNoBackups = false;
17
18 public XmlPatch(String file, bool noBackups)
19 {
20 fileName = file;
21 globalNoBackups = noBackups;
22 }
23
24 public XmlPatch(String file, String forceInFiles, bool noBackups)
25 {
26 fileName = file;
27 forceFiles = forceInFiles; //We support apply the operation in diverse forced files (NameOfFile parameter will be ignored)
28 globalNoBackups = noBackups;
29 }
30
31 /// <summary>
32 /// Applies the patch file. Returns true if successful otherwise returns false.
33 /// </summary>
34 /// <returns></returns>
35 public bool startPatch()
36 {
37 string line;
38
39 // Read the file and display it line by line.
40 System.IO.StreamReader file = new System.IO.StreamReader(fileName);
41
42 while ((line = file.ReadLine()) != null) //read while we don't reach the end of the file
43 {
44 if (line.StartsWith("@ADDTO "))
45 {
46 string operation = line;
47 string xmlToInject = "";
48
49 file.ReadLine(); //ignore <xml> start header
50 while ((line = file.ReadLine()) != "</xml>")
51 {
52 xmlToInject += line + "\n"; //get all the xml that will be injected
53 }
54 if (!addOperation(operation, xmlToInject))
55 {
56 Program.printAppError(Program.appErrors.PATCH_ADDTO_PROCESS_ERROR, "Error while performing adding operation in patch file. Aborting...");
57 return false;
58 }
59 }
60 else if (line.StartsWith("@REMOVE "))
61 {
62 if (!removeOperation(line))
63 {
64 Program.printAppError(Program.appErrors.PATCH_REMOVE_PROCESS_ERROR, "Error while performing remove operation in patch file. Aborting...");
65 return false;
66 }
67 }
68 else if (line.StartsWith("@COMMAND "))
69 {
70 if (!executeCommand(line))
71 {
72 Program.printAppError(Program.appErrors.PATCH_COMMAND_PROCESS_ERROR, "Error while performing command operation in patch file. Aborting...");
73 return false;
74 }
75 }
76 }
77
78 file.Close();
79
80 return true;
81 }
82
83 /// <summary>
84 /// Inserts xml in a desired Element. Returns true or false if it succeeds
85 /// </summary>
86 /// <param name="operation"></param>
87 /// <param name="xmlToInject"></param>
88 /// <returns></returns>
89 private bool addOperation(string operation, string xmlToInject)
90 {
91 //@ADDTO File "example.xml" ParentElement "Animation" Element "Lookup"
92
93 string File = "", ParentElement = "", Element = "";
94
95 //---------------------------------------------------Parse Operation command (start)
96 try
97 {
98 if (forceFiles == null)
99 {
100 File = getPatchParameter(operation, "File");
101 }
102 else
103 {
104 File = forceFiles;
105 }
106
107 ParentElement = getPatchParameter(operation, "ParentElement"); //Get the ParentElement
108
109 Element = getPatchParameter(operation, "Element"); //Get the Element
110 }
111 catch (Exception e)
112 {
113 Program.printAppError(Program.appErrors.PATCH_ADDTO_ERROR_PARSING_XML, "Error parsing addOperation in Patch file.\n" + e.ToString());
114 return false;
115 }
116
117 if (Element == "")
118 {
119 return false;
120 }
121
122 //---------------------------------------------------Parse Operation command (end)
123 List<String> filesToProcess = new List<String>();
124 if (File == "")
125 {
126 filesToProcess = Util.getAllXmlFiles(); //no file specified, use all xml files found in same folder
127 }
128 else if (Util.containsWildcard(File))
129 {
130 filesToProcess = Util.getXmlFilesWildcard(File);
131 }
132 else
133 {
134 filesToProcess.Add(File);
135 }
136
137 //---------------------------------------------------XML Injection (start)
138 foreach (String currFile in filesToProcess)
139 {
140 if (!this.globalNoBackups && !Util.ContainsIgnoreCase(operation, "NoBackups")) // only skip backup if specified via global parameter or in patch file
141 {
142 Util.backupFile(currFile);
143 }
144
145 XmlDocument xdoc = new XmlDocument();
146 xdoc.Load(currFile);
147
148 List<XmlNode> myElements = new List<XmlNode>();
149 Util.getAllSpecificElements(xdoc.DocumentElement, ref myElements, Element, ParentElement); //Returns all after "Oni" element
150
151 if (myElements.Count == 0)
152 {
153 Program.printAppError(Program.appErrors.PATCH_ELEMENT_NOT_FOUND, "Error in addOperation in Patch file: the element specified doesn't exist.");
154 return false;
155 }
156
157 try
158 {
159 XmlNode newXml = xdoc.ImportNode(Util.stringToXmlNode(xmlToInject), true); //necessary to import node or ArgumentException will be thrown when appending
160
161 myElements[myElements.Count - 1].AppendChild(newXml); // Append the code after last element
162
163 xdoc.Save(currFile);
164 }
165 catch (XmlException e)
166 {
167 Program.printAppError(Program.appErrors.PATCH_ADDTO_ERROR_PARSING_XML, "Error parsing xml to addOperation in Patch file.\n" + e.ToString());
168 return false;
169 }
170 }
171 //---------------------------------------------------XML Injection (end)
172
173 return true;
174 }
175
176 /// <summary>
177 /// Removes a xml element, right now it removes the first element it finds with matchs "Element" and "ParentElement" parameters
178 /// </summary>
179 /// <param name="operation"></param>
180 /// <returns>true or false depending if succeed or not</returns>
181 private bool removeOperation(string operation)
182 {
183 //@REMOVE File "example.xml" ParentElement "Particles" Element "Particle"
184
185 string File = "", ParentElement = "", Element = "";
186
187 //---------------------------------------------------Parse Operation command (start)
188 try
189 {
190 if (forceFiles == null)
191 {
192 File = getPatchParameter(operation, "File");
193 }
194 else
195 {
196 File = forceFiles;
197 }
198
199 ParentElement = getPatchParameter(operation, "ParentElement"); //Get the ParentElement
200
201 Element = getPatchParameter(operation, "Element"); //Get the Element
202 }
203 catch (Exception e)
204 {
205 Program.printAppError(Program.appErrors.PATCH_REMOVE_PROCESS_ERROR, "Error parsing removeOperation in Patch file.\n" + e.ToString());
206 return false;
207 }
208
209 if (Element == "")
210 {
211 return false;
212 }
213
214 //---------------------------------------------------Parse Operation command (end)
215
216 List<String> filesToProcess = new List<String>();
217 if (File == "")
218 {
219 filesToProcess = Util.getAllXmlFiles(); //no file specified, use all xml files found in same folder
220 }
221 else if (Util.containsWildcard(File))
222 {
223 filesToProcess = Util.getXmlFilesWildcard(File);
224 }
225 else
226 {
227 filesToProcess.Add(File);
228 }
229
230 //---------------------------------------------------XML Remove (start)
231
232 foreach (String currFile in filesToProcess)
233 {
234
235 if (!this.globalNoBackups && !Util.ContainsIgnoreCase(operation, "NoBackups")) // only skip backup if specified via global parameter or in patch file
236 {
237 Util.backupFile(currFile);
238 }
239
240 XmlDocument xdoc = new XmlDocument();
241 xdoc.Load(currFile);
242
243 List<XmlNode> myElements = new List<XmlNode>();
244 Util.getAllSpecificElements(xdoc.DocumentElement, ref myElements, Element, ParentElement); //Returns all after "Oni" element
245
246 if (myElements.Count == 0)
247 {
248 Program.printAppError(Program.appErrors.PATCH_ELEMENT_NOT_FOUND, "Error in removeOperation in Patch file: the element specified doesn't exist.");
249 return false;
250 }
251
252 myElements[0].ParentNode.RemoveChild(myElements[0]); // Removes the first occurrence which matches the "Element" and "ParentElement" given
253
254 xdoc.Save(currFile);
255
256 }
257 //---------------------------------------------------XML Remove (end)
258
259
260 return true;
261 }
262
263 /// <summary>
264 ///
265 /// </summary>
266 /// <param name="command"></param>
267 /// <returns>true or false depending if succeed or not</returns>
268 private bool executeCommand(string command)
269 {
270 //---------------------------------------------------Parse Operation command (start)
271
272 command = command.Replace("@COMMAND ", ""); //get only the command to process
273
274 if (command.Trim() == "")
275 {
276 Program.printAppError(Program.appErrors.PATCH_COMMAND_NOT_FOUND, "Error parsing commandOperation in Patch file: Command is empty.");
277 return false;
278 }
279
280 try
281 {
282 if (forceFiles != null)
283 {
284 string paramType = "";
285
286 // Filename already exists?
287 if (command.IndexOf("filename:") != -1)
288 {
289 paramType = "filename:";
290 }
291 else if (command.IndexOf("filename=") != -1)
292 {
293 paramType = "filename=";
294 }
295 // Add the filename if it doesn't exists
296 else
297 {
298 command = command.Insert(command.Length-1," -filename:" + this.forceFiles); // -1 to be inside quotes
299 }
300
301 if (paramType != "")
302 {
303 int startIdx = command.IndexOf(paramType) + paramType.Length;
304 int endIdx = command.IndexOf(" ", startIdx); // it may end with space
305 if (endIdx == -1)
306 {
307 endIdx = command.IndexOf("\"", startIdx); // or with quotes
308 }
309 string currFilename = command.Substring(startIdx, endIdx - startIdx);
310 command = command.Replace(currFilename, this.forceFiles);
311 }
312
313 }
314
315 if (this.globalNoBackups && !Util.ContainsIgnoreCase(command,"nobackups")) // add noBackup flag if provided as global parameter
316 {
317 command = command.Insert(command.Length - 1, " -nobackups"); // -1 to be inside quotes
318 }
319
320 command = command.Replace("\"", ""); // remove quotes
321
322 Program.Main(command.Split(' ')); // use the current process is more efficient than start a new one
323 }
324 catch (Exception e)
325 {
326 Program.printAppError(Program.appErrors.PATCH_COMMAND_PROCESS_ERROR, "Error processing command in Patch file.\n" + e.ToString());
327 return false;
328 }
329
330 return true;
331 }
332
333 private string getPatchParameter(string line, string parameterName)
334 {
335 string result = "";
336 int startIdx = 0, endIdx = 0;
337
338 string temp = parameterName + " \"";
339
340 startIdx = line.IndexOf(temp);
341 if (startIdx != -1) //we have Parameter specified
342 {
343 startIdx += temp.Length;
344 endIdx = line.IndexOf("\"", startIdx);
345 result = line.Substring(startIdx, endIdx - startIdx); //Get the parameter value
346 }
347
348 return result;
349 }
350 }
351}
Note: See TracBrowser for help on using the repository browser.