Mercurial > repos > IBDev-IBBoard.WarFoundry.API
annotate api/Factories/Xml/WarFoundryXmlFactory.cs @ 23:f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
* Add missing spaces to Cats and Core XSD
* Fix some incorrect namespaces in Race XSD
* Copy schemas to output dir on build
* Make WarFoundryXmlFactory validate against Schemas
* Make WarFoundryLoader handle failed file loads slightly differently so that we can log out as a warning
* Correctly structure "simpleContent" sections of Race XSD
Still to do:
* Work out why Race XSD doesn't like core:nonNegativeDecimal but appears to be fine with core:percentage
* Migrate test files to define namespaces and make sure they match the structure
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Thu, 12 Mar 2009 21:35:17 +0000 |
parents | a99d3b8466ba |
children | 457c9357dd64 |
rev | line source |
---|---|
15 | 1 // This file (WarFoundryXmlFactory.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 IBBoard. |
0 | 2 // |
15 | 3 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license. |
0 | 4 |
5 using System; | |
6 using System.IO; | |
7 using System.Xml; | |
8 using System.Xml.Schema; | |
9 using System.Collections.Generic; | |
10 using System.Text; | |
11 using IBBoard; | |
12 using IBBoard.IO; | |
13 using IBBoard.Lang; | |
14 using IBBoard.Logging; | |
15 using IBBoard.Xml; | |
16 using IBBoard.WarFoundry.API.Requirements; | |
17 using IBBoard.WarFoundry.API.Objects; | |
18 using ICSharpCode.SharpZipLib.Zip; | |
19 | |
20 namespace IBBoard.WarFoundry.API.Factories.Xml | |
21 { | |
22 /// <summary> | |
10 | 23 /// The WarFoundryXmlFactory loads WarFoundry classes from the native "XML in a zip" file format. Files are validated using the schema for the file type, so structurally invalid files should be identified at initial load. |
0 | 24 /// </summary> |
25 public class WarFoundryXmlFactory : AbstractNativeWarFoundryFactory | |
26 { | |
17
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
27 private static WarFoundryXmlFactory factory; |
23
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
28 private XmlReaderSettings settings; |
0 | 29 private Dictionary<IWarFoundryObject, XmlDocument> extraData = new Dictionary<IWarFoundryObject, XmlDocument>(); |
30 private XmlResolver xmlResolver; | |
31 | |
17
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
32 public static AbstractNativeWarFoundryFactory GetFactory() |
0 | 33 { |
17
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
34 if (factory == null) |
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
35 { |
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
36 factory = new WarFoundryXmlFactory(); |
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
37 } |
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
38 |
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
39 return factory; |
0 | 40 } |
41 | |
42 protected WarFoundryXmlFactory() : base() | |
43 { | |
44 xmlResolver = new IBBXmlResolver(Constants.ExecutablePath); | |
45 } | |
46 | |
47 protected override bool CheckCanFindArmyFileContent(ZipFile file) | |
48 { | |
49 return file.FindEntry("data.armyx", true) > -1; | |
50 } | |
51 | |
52 protected override bool CheckCanFindSystemFileContent(ZipFile file) | |
53 { | |
54 return file.FindEntry("data.systemx", true) > -1; | |
55 } | |
56 | |
57 protected override bool CheckCanFindRaceFileContent(ZipFile file) | |
58 { | |
59 return file.FindEntry("data.racex", true) > -1; | |
60 } | |
61 | |
62 protected XmlElement GetRootElementFromStream(Stream stream, WarFoundryXmlElementName elementName) | |
63 { | |
64 XmlDocument doc = CreateXmlDocumentFromStream(stream); | |
65 XmlElement elem = (XmlElement)doc.LastChild; | |
66 | |
67 if (!elem.Name.Equals(elementName.Value)) | |
68 { | |
69 throw new InvalidFileException(String.Format("Root element of XML was not valid. Expected {0} but got {1}", elementName.Value, elem.Name)); | |
70 } | |
71 | |
72 return elem; | |
73 } | |
74 | |
75 protected override Stream GetArmyDataStream(ZipFile file) | |
76 { | |
77 return file.GetInputStream(file.FindEntry("data.armyx", true)); | |
78 } | |
79 | |
80 protected override Army CreateArmyFromStream (ZipFile file, Stream dataStream) | |
81 { | |
82 XmlElement elem = GetRootElementFromStream(dataStream, WarFoundryXmlElementName.ARMY_ELEMENT); | |
83 return CreateArmyFromElement(file, elem); | |
84 } | |
85 | |
86 private Army CreateArmyFromElement(ZipFile file, XmlElement elem) | |
87 { | |
88 string name = elem.GetAttribute("name"); | |
89 string systemID = elem.GetAttribute("gameSystem"); | |
90 GameSystem system = WarFoundryLoader.GetDefault().GetGameSystem(systemID); | |
91 string raceID = elem.GetAttribute("race"); | |
92 Race race = WarFoundryLoader.GetDefault().GetRace(system, raceID); | |
93 string pointsString = elem.GetAttribute("maxPoints"); | |
94 int points = 0; | |
95 | |
96 try | |
97 { | |
98 points = int.Parse(pointsString); | |
99 } | |
100 catch(FormatException) | |
101 { | |
102 throw new FormatException("Attribute 'maxPoints' of army '"+name+"' was not a valid number"); | |
103 } | |
104 | |
10 | 105 Army army = new Army(race, name, points, file); |
0 | 106 extraData[army] = elem.OwnerDocument; |
107 return army; | |
108 } | |
109 | |
110 protected override Stream GetGameSystemDataStream (ZipFile file) | |
111 { | |
112 return file.GetInputStream(file.FindEntry("data.systemx", true)); | |
113 } | |
114 | |
115 protected override GameSystem CreateGameSystemFromStream (ZipFile file, Stream dataStream) | |
116 { | |
117 XmlElement elem = GetRootElementFromStream(dataStream, WarFoundryXmlElementName.SYSTEM_ELEMENT); | |
118 LogNotifier.Debug(GetType(), "Create GameSystem"); | |
119 return CreateSystemFromElement(file, elem); | |
120 } | |
121 | |
122 private GameSystem CreateSystemFromElement(ZipFile file, XmlElement elem) | |
123 { | |
124 string id = elem.GetAttribute("id"); | |
125 string name = elem.GetAttribute("name"); | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
126 GameSystem system = new GameSystem(id, name, this); |
0 | 127 extraData[system] = elem.OwnerDocument; |
128 return system; | |
129 } | |
130 | |
131 protected override Stream GetRaceDataStream (ZipFile file) | |
132 { | |
133 return file.GetInputStream(file.FindEntry("data.racex", true)); | |
134 } | |
135 | |
136 protected override Race CreateRaceFromStream (ZipFile file, Stream dataStream) | |
137 { | |
138 XmlElement elem = GetRootElementFromStream(dataStream, WarFoundryXmlElementName.RACE_ELEMENT); | |
139 LogNotifier.Debug(GetType(), "Create Race"); | |
140 return CreateRaceFromElement(file, elem); | |
141 } | |
142 | |
143 private Race CreateRaceFromElement(ZipFile file, XmlElement elem) | |
144 { | |
145 string id = elem.GetAttribute("id"); | |
146 string subid = elem.GetAttribute("subid"); | |
147 string systemID = elem.GetAttribute("system"); | |
148 string name = elem.GetAttribute("name"); | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
149 Race race = new Race(id, subid, name, systemID, this); |
0 | 150 extraData[race] = elem.OwnerDocument; |
151 return race; | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
152 } |
0 | 153 |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
154 public override void CompleteLoading(IWarFoundryStagedLoadObject obj) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
155 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
156 LogNotifier.DebugFormat(GetType(), "Complete loading of {0} with ID {1}", obj.GetType().Name, obj.ID); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
157 |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
158 if (obj is GameSystem) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
159 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
160 CompleteLoading((GameSystem)obj); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
161 } |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
162 else if (obj is Race) |
0 | 163 { |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
164 CompleteLoading((Race)obj); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
165 } |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
166 } |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
167 |
10 | 168 public XmlNode GetExtraData(IWarFoundryObject obj) |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
169 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
170 XmlDocument extra = null; |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
171 extraData.TryGetValue(obj, out extra); |
10 | 172 XmlNode node = null; |
173 | |
174 if (extra !=null) | |
175 { | |
176 node = extra.LastChild; | |
177 } | |
178 | |
179 return node; | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
180 } |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
181 |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
182 public void CompleteLoading(GameSystem system) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
183 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
184 if (system.IsFullyLoaded) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
185 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
186 LogNotifier.DebugFormat(GetType(), "Object of type GameSystem with ID {0} is already fully loaded", system.ID); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
187 return; |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
188 } |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
189 |
10 | 190 XmlNode elem = GetExtraData(system); |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
191 XmlNode catsElem = elem.FirstChild; |
10 | 192 LoadCategoriesForSystem(system, elem); |
193 | |
194 XmlElement statsElem = (XmlElement)catsElem.NextSibling; | |
195 LoadSystemStatsFromElement(statsElem, system); | |
196 string defaultStatsID = statsElem.GetAttribute("defaultStats"); | |
197 | |
198 LogNotifier.DebugFormat(GetType(), "Completed loading of GameSystem with ID {0}", system.Name); | |
199 system.StandardSystemStatsID = defaultStatsID; | |
200 system.SetAsFullyLoaded(); | |
201 } | |
202 | |
203 private void LoadCategoriesForSystem(GameSystem system, XmlNode elem) | |
204 { | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
205 WarFoundryObject tempObj; |
10 | 206 |
207 foreach (XmlElement cat in elem.SelectNodes("//"+WarFoundryXmlElementName.CATEGORY_ELEMENT.Value)) | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
208 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
209 tempObj = CreateObjectFromElement(cat); |
0 | 210 |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
211 if (tempObj is Category) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
212 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
213 system.AddCategory((Category)tempObj); |
0 | 214 } |
215 else | |
216 { | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
217 LogNotifier.WarnFormat(GetType(), "Object for string {0} was not of type Category", cat.OuterXml); |
0 | 218 } |
219 } | |
220 } | |
221 | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
222 public void CompleteLoading(Race race) |
0 | 223 { |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
224 if (race.IsFullyLoaded) |
0 | 225 { |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
226 LogNotifier.DebugFormat(GetType(), "Object of type Race with ID {0} is already fully loaded", race.ID); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
227 return; |
0 | 228 } |
229 | |
10 | 230 XmlNode elem = GetExtraData(race); |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
231 XmlNode colNode = elem.FirstChild; |
11
5a1df00b0359
Re #9 - Make WarFoundry API load files in small methods
IBBoard <dev@ibboard.co.uk>
parents:
10
diff
changeset
|
232 |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
233 foreach (XmlElement node in colNode.ChildNodes) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
234 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
235 UnitType type = CreateUnitTypeFromElement(node, race, race.GameSystem); |
11
5a1df00b0359
Re #9 - Make WarFoundry API load files in small methods
IBBoard <dev@ibboard.co.uk>
parents:
10
diff
changeset
|
236 race.AddUnitType(type); |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
237 } |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
238 |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
239 colNode = colNode.NextSibling; |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
240 |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
241 if (colNode!=null && colNode.Name == WarFoundryXmlElementName.CATEGORIES_ELEMENT.Value) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
242 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
243 foreach (XmlElement node in colNode.ChildNodes) |
0 | 244 { |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
245 race.AddCategory(CreateCategoryFromElement(node)); |
0 | 246 } |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
247 |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
248 colNode = colNode.NextSibling; |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
249 } |
11
5a1df00b0359
Re #9 - Make WarFoundry API load files in small methods
IBBoard <dev@ibboard.co.uk>
parents:
10
diff
changeset
|
250 |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
251 if (colNode!=null && colNode.Name == WarFoundryXmlElementName.RACE_EQUIPMENT_ITEMS_ELEMENT.Value) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
252 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
253 foreach (XmlElement node in colNode.ChildNodes) |
0 | 254 { |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
255 EquipmentItem item = CreateEquipmentItemFromElement(node, race); |
11
5a1df00b0359
Re #9 - Make WarFoundry API load files in small methods
IBBoard <dev@ibboard.co.uk>
parents:
10
diff
changeset
|
256 race.AddEquipmentItem(item); |
0 | 257 } |
258 } | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
259 |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
260 Dictionary<string, Ability> raceAbilities = new Dictionary<string, Ability>(); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
261 //TODO: Load abilities |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
262 race.SetAbilities(raceAbilities); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
263 race.SetAsFullyLoaded(); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
264 LogNotifier.DebugFormat(GetType(), "Completed loading of Race with ID {0}", race.Name); |
0 | 265 } |
266 | |
267 protected XmlDocument CreateXmlDocumentFromStream(Stream stream) | |
268 { | |
269 XmlDocument doc = new XmlDocument(); | |
23
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
270 XmlReader reader = XmlReader.Create(stream, GetReaderSettings()); |
0 | 271 |
272 try | |
273 { | |
274 doc.Load(reader); | |
275 } | |
276 //Don't catch XMLSchemaExceptions - let them get thrown out | |
277 finally | |
278 { | |
279 reader.Close(); | |
280 } | |
281 | |
282 if (doc.ChildNodes.Count!=3) | |
283 { | |
284 throw new InvalidFileException(Translation.GetTranslation("ErrorInvalidXmlFile", "XML file was not a valid XML file. It should contain three child nodes - XML definition, DocType and root node.")); | |
285 } | |
286 | |
287 return doc; | |
23
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
288 } |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
289 |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
290 /// <summary> |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
291 /// Lazy-getter for XML reader settings. May throw a <see cref="InvalidDataException"/> if there is a problem with the translation schema. |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
292 /// </summary> |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
293 /// <returns> |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
294 /// A <see cref="XmlReaderSettings"/> with the default values for validating the translation document against the translation schema |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
295 /// </returns> |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
296 private XmlReaderSettings GetReaderSettings() |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
297 { |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
298 if (settings == null) |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
299 { |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
300 try |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
301 { |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
302 settings = new XmlReaderSettings(); |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
303 settings.ValidationType = ValidationType.Schema; |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
304 settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings; |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
305 settings.ValidationEventHandler+= new ValidationEventHandler(ValidationEventMethod); |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
306 XmlSchemaSet cache = new XmlSchemaSet(); |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
307 cache.Add("http://ibboard.co.uk/warfoundry/core", IBBoard.Constants.ExecutablePath + "/dtds/warfoundry-core.xsd"); |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
308 cache.Add("http://ibboard.co.uk/warfoundry/cats", IBBoard.Constants.ExecutablePath + "/dtds/warfoundry-cats.xsd"); |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
309 cache.Add("http://ibboard.co.uk/warfoundry/race", IBBoard.Constants.ExecutablePath + "/dtds/race.xsd"); |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
310 cache.Add("http://ibboard.co.uk/warfoundry/system", IBBoard.Constants.ExecutablePath + "/dtds/system.xsd"); |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
311 settings.Schemas.Add(cache); |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
312 } |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
313 catch (DirectoryNotFoundException ex) |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
314 { |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
315 throw new InvalidDataException("Problem validating schema for WarFoundry data: " + ex.Message, ex); |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
316 } |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
317 catch (XmlSchemaException ex) |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
318 { |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
319 throw new InvalidDataException("Problem validating schema for WarFoundry data: " + ex.Message, ex); |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
320 } |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
321 catch (XmlException ex) |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
322 { |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
323 throw new InvalidDataException("Problem reading data for schema: " + ex.Message, ex); |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
324 } |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
325 } |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
326 |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
327 return settings; |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
328 } |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
329 |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
330 private void ValidationEventMethod(object sender, ValidationEventArgs e) |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
331 { |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
332 throw new InvalidDataException("Problem validating against schema for WarFoundry data: " + e.Exception.Message, e.Exception); |
0 | 333 } |
334 | |
335 protected XmlDocument CreateXmlDocumentFromString(string xmlString) | |
336 { | |
337 XmlReaderSettings settings = new XmlReaderSettings(); | |
338 settings.XmlResolver = xmlResolver; | |
339 settings.ValidationType = ValidationType.DTD; | |
340 settings.ProhibitDtd = false; | |
341 settings.ValidationEventHandler+= new ValidationEventHandler(ValidationEventMethod); | |
342 XmlReader reader = XmlReader.Create(new MemoryStream(Encoding.UTF8.GetBytes(xmlString)), settings); | |
343 XmlDocument doc = new XmlDocument(); | |
344 | |
345 try | |
346 { | |
347 doc.Load(reader); | |
348 } | |
349 catch(XmlSchemaException ex) | |
350 { | |
351 throw new InvalidFileException(Translation.GetTranslation("ErrorInvalidXmlString", "Failed to parse invalid XML string"), ex); | |
352 } | |
353 finally | |
354 { | |
355 //We might not need to make sure the memory stream is closed, but do it just in case | |
356 reader.Close(); | |
357 } | |
358 | |
359 if (doc.ChildNodes.Count!=3) | |
360 { | |
361 throw new InvalidFileException(String.Format(Translation.GetTranslation("ErrorInvalidXmlFile", "XML string was not a valid XML file. It should contain three child nodes - XML definition, DocType and root node."))); | |
362 } | |
363 | |
364 return doc; | |
365 } | |
366 | |
367 private WarFoundryObject CreateObjectFromElement(XmlElement elem) | |
368 { | |
369 WarFoundryObject obj = null; | |
370 LogNotifier.DebugFormat(GetType(), "Create object for <{0}>", elem.Name); | |
371 | |
372 if (elem.Name.Equals(WarFoundryXmlElementName.CATEGORY_ELEMENT.Value)) | |
373 { | |
374 LogNotifier.Debug(GetType(), "Create Category"); | |
375 obj = CreateCategoryFromElement(elem); | |
376 } | |
377 else | |
378 { | |
379 LogNotifier.Debug(GetType(), "No match"); | |
380 } | |
381 | |
382 return obj; | |
383 } | |
384 | |
385 private Category CreateCategoryFromElement(XmlElement elem) | |
386 { | |
387 string id = elem.GetAttribute("id"); | |
388 string name = elem.GetAttribute("name"); | |
9
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
389 int minPc, maxPc, minPts, maxPts, minChoices, maxChoices, baseValue, incValue, incAmount; |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
390 minPc = GetIntValueFromAttribute(elem, "minPercentage"); |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
391 maxPc = GetIntValueFromAttribute(elem, "maxPercentage"); |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
392 minPts = GetIntValueFromAttribute(elem, "minPoints"); |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
393 maxPts = GetIntValueFromAttribute(elem, "maxPoints"); |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
394 minChoices = GetIntValueFromAttribute(elem, "minChoices"); |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
395 maxChoices = GetIntValueFromAttribute(elem, "maxChoices"); |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
396 baseValue = GetIntValueFromAttribute(elem, "baseValue"); |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
397 incValue = GetIntValueFromAttribute(elem, "incValue"); |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
398 incAmount = GetIntValueFromAttribute(elem, "incAmount"); |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
399 |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
400 return new Category(id, name, minPts, maxPts, minPc, maxPc, minChoices, maxChoices, baseValue, incValue, incAmount); |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
401 } |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
402 |
10 | 403 private int GetIntValueFromAttribute(XmlElement elem, string attributeName) |
9
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
404 { |
0 | 405 try |
406 { | |
9
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
407 return int.Parse(elem.GetAttribute(attributeName)); |
0 | 408 } |
409 catch(FormatException) | |
410 { | |
9
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
411 throw new FormatException(String.Format("Attribute '{0}' of {1} with ID {2} was not a valid number", attributeName, elem.Name, elem.GetAttribute("id"))); |
0 | 412 } |
413 } | |
414 | |
415 private UnitType CreateUnitTypeFromElement(XmlElement elem, Race parentRace, GameSystem system) | |
416 { | |
417 string id = elem.GetAttribute("id"); | |
418 string name = elem.GetAttribute("typeName"); | |
12
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
419 UnitType type = new UnitType(id, name, parentRace); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
420 type.MinNumber = GetIntValueFromAttribute(elem, "minNum"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
421 type.MaxNumber = GetIntValueFromAttribute(elem, "maxNum"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
422 type.MinSize = GetIntValueFromAttribute(elem, "minSize"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
423 type.MaxSize = GetIntValueFromAttribute(elem, "maxSize"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
424 //TODO: Add base size |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
425 type.CostPerTrooper = GetIntValueFromAttribute(elem, "points"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
426 type.BaseUnitCost = GetIntValueFromAttribute(elem, "unitPoints"); |
0 | 427 |
428 XmlNode node = elem.FirstChild; | |
429 | |
430 foreach(XmlElement cat in node.ChildNodes) | |
431 { | |
12
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
432 string catID = cat.GetAttribute("catID"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
433 type.AddCategory(parentRace.GetCategory(catID)); |
0 | 434 } |
12
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
435 |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
436 string mainCatID = elem.GetAttribute("cat"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
437 type.MainCategory = parentRace.GetCategory(mainCatID); |
0 | 438 node = node.NextSibling; |
12
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
439 type.UnitStats = ParseUnitStats((XmlElement)node, system); |
0 | 440 //TODO: Add unit requirements |
441 | |
442 return type; | |
443 } | |
444 | |
445 private Stats ParseUnitStats(XmlElement elem, GameSystem system) | |
446 { | |
447 List<Stat> statsList = new List<Stat>(); | |
448 String statsID = elem.GetAttribute("statSet"); | |
449 SystemStats statsSet; | |
450 | |
451 if (statsID == "") | |
452 { | |
453 statsSet = system.StandardSystemStats; | |
454 } | |
455 else | |
456 { | |
6 | 457 statsSet = system.GetSystemStatsForID(statsID); |
0 | 458 } |
459 | |
460 Stats stats = new Stats(statsSet); | |
461 | |
462 foreach (XmlElement stat in elem.ChildNodes) | |
463 { | |
464 String statID = stat.GetAttribute("name"); | |
465 StatSlot slot = statsSet[statID]; | |
466 | |
467 if (slot!=null) | |
468 { | |
469 statsList.Add(new Stat(slot, stat.InnerText)); | |
470 } | |
471 else | |
472 { | |
473 throw new InvalidFileException("The stat "+statID+" was not found in stats set "+statsID); | |
474 } | |
475 } | |
476 | |
477 stats.SetStats(statsList); | |
478 | |
479 return stats; | |
480 } | |
481 | |
6 | 482 private void LoadSystemStatsFromElement(XmlElement elem, GameSystem system) |
0 | 483 { |
484 foreach (XmlElement stats in elem.ChildNodes) | |
485 { | |
486 SystemStats sysStats = CreateSystemStatsFromElement(stats); | |
6 | 487 system.AddSystemStats(sysStats); |
0 | 488 } |
489 } | |
490 | |
491 private SystemStats CreateSystemStatsFromElement(XmlElement elem) | |
492 { | |
493 List<StatSlot> slots = new List<StatSlot>(); | |
494 string id = elem.GetAttribute("id"); | |
495 | |
496 foreach (XmlElement slot in elem.ChildNodes) | |
497 { | |
498 StatSlot statSlot = new StatSlot(slot.GetAttribute("name")); | |
499 slots.Add(statSlot); | |
500 } | |
501 | |
502 return new SystemStats(id, slots.ToArray()); | |
503 } | |
504 | |
505 private EquipmentItem CreateEquipmentItemFromElement(XmlElement elem, Race race) | |
506 { | |
507 string id = elem.GetAttribute("id"); | |
508 string name = elem.GetAttribute("name"); | |
509 float cost = 0, min = 0, max = 0; | |
510 ArmourType armourType; | |
511 | |
512 try | |
513 { | |
514 cost = float.Parse(elem.GetAttribute("cost")); | |
515 } | |
516 catch(FormatException) | |
517 { | |
518 throw new FormatException("Attribute 'cost' of equipment item "+id+" was not a valid number"); | |
519 } | |
520 | |
521 try | |
522 { | |
523 min = float.Parse(elem.GetAttribute("min")); | |
524 } | |
525 catch(FormatException) | |
526 { | |
527 throw new FormatException("Attribute 'min' of equipment item "+id+" was not a valid number"); | |
528 } | |
529 | |
530 try | |
531 { | |
532 max = float.Parse(elem.GetAttribute("max")); | |
533 } | |
534 catch(FormatException) | |
535 { | |
536 throw new FormatException("Attribute 'max' of equipment item "+id+" was not a valid number"); | |
537 } | |
538 | |
539 try | |
540 { | |
541 armourType = (ArmourType)Enum.Parse(typeof(ArmourType), elem.GetAttribute("armourType")); | |
542 } | |
543 catch(FormatException) | |
544 { | |
545 throw new InvalidFileException("Attribute 'armourType' of equipment "+id+" was not a valid value from the enumeration"); | |
546 } | |
547 | |
548 if (elem.ChildNodes.Count>0) | |
549 { | |
550 //It has stats! | |
551 //TODO: Parse equipment stats | |
552 } | |
553 | |
554 return new EquipmentItem(id, name, cost, min, max, armourType, race); | |
555 } | |
556 } | |
557 } |