--- /dev/null
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Runtime.Serialization;\r
+using System.Text.RegularExpressions;\r
+using Microsoft.Xna.Framework;\r
+using Microsoft.Xna.Framework.Content;\r
+using Microsoft.Xna.Framework.Graphics;\r
+\r
+namespace CarFire\r
+{\r
+ /// <summary>\r
+ /// This class will be instantiated by the XNA Framework Content\r
+ /// Pipeline to read cfmap files from binary .xnb format.\r
+ /// </summary>\r
+ public class MapReader : ContentTypeReader<Map>\r
+ {\r
+ public class ParserException : System.ApplicationException\r
+ {\r
+ public ParserException()\r
+ {\r
+ }\r
+\r
+ public ParserException(string message) :\r
+ base(message)\r
+ {\r
+ }\r
+\r
+ public ParserException(string message, System.Exception inner) :\r
+ base(message, inner)\r
+ {\r
+ }\r
+\r
+ protected ParserException(SerializationInfo info, StreamingContext context) :\r
+ base(info, context)\r
+ {\r
+ }\r
+ }\r
+\r
+ ContentReader mInput;\r
+ int mLineNumber = 0;\r
+ int mExpectedNumberOfLines;\r
+\r
+ Map.Data mData;\r
+\r
+\r
+ protected override Map Read(ContentReader input, Map existingInstance)\r
+ {\r
+ mInput = input;\r
+ mExpectedNumberOfLines = mInput.ReadInt32();\r
+\r
+ ReadData();\r
+\r
+ return new Map(mData);\r
+ }\r
+\r
+\r
+ #region Private Reading Methods\r
+ \r
+ string ReadLine()\r
+ {\r
+ return mInput.ReadString();\r
+ }\r
+\r
+ void ReadData()\r
+ {\r
+ mData = new Map.Data();\r
+\r
+ while (mLineNumber < mExpectedNumberOfLines)\r
+ {\r
+ string line = ReadLine();\r
+ mLineNumber++;\r
+\r
+ while (line != null)\r
+ {\r
+ if (!IsLineSignificant(line)) break;\r
+\r
+ string section = Parse.IniSectionHeader(line);\r
+ if (section != null)\r
+ {\r
+ if (section == "metadata")\r
+ {\r
+ line = ReadMetadataSection();\r
+ }\r
+ else if (section == "maptable")\r
+ {\r
+ line = ReadMapTableSection();\r
+ }\r
+ else if (section.Length == 1)\r
+ {\r
+ line = ReadEntitySection(section[0]);\r
+ }\r
+ else\r
+ {\r
+ ThrowException("Unknown section", section);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ ThrowException("Unexpected text", line);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ string ReadMetadataSection()\r
+ {\r
+ while (mLineNumber < mExpectedNumberOfLines)\r
+ {\r
+ string line = ReadLine();\r
+ mLineNumber++;\r
+\r
+ if (!IsLineSignificant(line)) continue;\r
+\r
+ string[] pair = Parse.KeyValuePair(line);\r
+ if (pair != null)\r
+ {\r
+ if (pair[0] == "type")\r
+ {\r
+ object type = Parse.Constant<Map.Type>(pair[1]);\r
+ if (type != null)\r
+ {\r
+ mData.Type = (Map.Type)type;\r
+ }\r
+ else\r
+ {\r
+ ThrowException("Invalid type", pair[1]);\r
+ }\r
+ }\r
+ else if (pair[0] == "dimensions")\r
+ {\r
+ Point? dimensions = Parse.Coordinates(pair[1]);\r
+ if (dimensions != null)\r
+ {\r
+ mData.Dimensions = dimensions.Value;\r
+ if (mData.Dimensions.X <= 0 || mData.Dimensions.Y <= 0)\r
+ {\r
+ ThrowException("Invalid dimensions", pair[1]);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ ThrowException("Invalid value", pair[1]);\r
+ }\r
+ }\r
+ else if (pair[0] == "tileset")\r
+ {\r
+ string tileset = Parse.String(pair[1]);\r
+ if (tileset != null)\r
+ {\r
+ mData.Tileset = tileset;\r
+ }\r
+ else\r
+ {\r
+ ThrowException("Invalid tileset", pair[1]);\r
+ }\r
+ }\r
+ else if (pair[0] == "numplayers")\r
+ {\r
+ int[] numPlayers = Parse.Range(pair[1]);\r
+ if (numPlayers != null)\r
+ {\r
+ mData.MinNumPlayers = numPlayers[0];\r
+ mData.MaxNumPlayers = numPlayers[1];\r
+ if (mData.MinNumPlayers <= 0 || mData.MaxNumPlayers <= 0 ||\r
+ mData.MinNumPlayers > mData.MaxNumPlayers)\r
+ {\r
+ ThrowException("Invalid range", pair[1]);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ ThrowException("Invalid value", pair[1]);\r
+ }\r
+ }\r
+ else if (pair[0] == "author")\r
+ {\r
+ string author = Parse.String(pair[1]);\r
+ if (author != null)\r
+ {\r
+ mData.Author = author;\r
+ }\r
+ else\r
+ {\r
+ ThrowException("Invalid value", pair[1]);\r
+ }\r
+ }\r
+ else if (pair[0] == "levelname")\r
+ {\r
+ string level = Parse.String(pair[1]);\r
+ if (level != null)\r
+ {\r
+ mData.Name = level;\r
+ }\r
+ else\r
+ {\r
+ ThrowException("Invalid value", pair[1]);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ Console.WriteLine("Unimplemented key: " + pair[0]);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ return line;\r
+ }\r
+ }\r
+\r
+ return null;\r
+ }\r
+\r
+ string ReadMapTableSection()\r
+ {\r
+ if (mData.Dimensions.X == 0 || mData.Dimensions.Y == 0)\r
+ {\r
+ ThrowException("Unexpected section", "You must define the map dimensions before this section.");\r
+ }\r
+\r
+ mData.Grid = new char[mData.Dimensions.X, mData.Dimensions.Y];\r
+\r
+ int y;\r
+ for (y = 0; y < mData.Dimensions.Y && mLineNumber < mExpectedNumberOfLines; y++)\r
+ {\r
+ string line = ReadLine();\r
+ mLineNumber++;\r
+\r
+ if (line.Length < mData.Dimensions.X)\r
+ {\r
+ ThrowException("Not enough characters", "Expecting " + mData.Dimensions.X + " characters.");\r
+ }\r
+\r
+ for (int x = 0; x < mData.Dimensions.X; x++)\r
+ {\r
+ mData.Grid[x, y] = line[x];\r
+ }\r
+ }\r
+\r
+ if (y < mData.Dimensions.Y)\r
+ {\r
+ ThrowException("Unexpected ", "");\r
+ }\r
+\r
+ return null;\r
+ }\r
+\r
+ string ReadEntitySection(char entity)\r
+ {\r
+ while (mLineNumber < mExpectedNumberOfLines)\r
+ {\r
+ string line = ReadLine();\r
+ mLineNumber++;\r
+\r
+ string[] pair = Parse.KeyValuePair(line);\r
+ if (pair != null)\r
+ {\r
+ // TODO\r
+ }\r
+ else\r
+ {\r
+ return line;\r
+ }\r
+ }\r
+\r
+ return null;\r
+ }\r
+\r
+ #endregion\r
+\r
+\r
+ #region Private Methods\r
+\r
+ bool IsLineSignificant(string line)\r
+ {\r
+ if (line.Length == 0 || Regex.IsMatch(line, @"^;|^\s*$")) return false;\r
+ return true;\r
+ }\r
+\r
+ void ThrowException(string problem, string text)\r
+ {\r
+ throw new ParserException(problem + " on line " + mLineNumber + ": " + text);\r
+ }\r
+\r
+ #endregion\r
+ }\r
+}\r