static void ReadObjectGroup(XmlNode node, ref Map map)
        {
            ObjectGroup r = new ObjectGroup();
            r.Name = node.ReadTag("name");
            r.X = node.ReadInt("x");
            r.Y = node.ReadInt("y");
            r.Width = node.ReadInt("width");
            r.Height = node.ReadInt("height");

            if (node.HasChildNodes)
            {
                ColorConverter cc = new ColorConverter();
                foreach (XmlNode c in node.ChildNodes)
                {
                    MapObject o = new MapObject();
                    o.Name = c.ReadTag("name");
                    o.Type = c.ReadTag("type");
                    o.X = c.ReadInt("x");
                    o.Y = c.ReadInt("y");
                    o.Width = c.ReadInt("width");
                    o.Height = c.ReadInt("height");
                    o.Gid = c.ReadInt("gid", -1);

                    if (c.HasChildNodes)
                    {
                        foreach (XmlNode d in c.ChildNodes)
                        {
                            switch (d.Name)
                            {
                                case "properties":
                                    foreach (XmlNode e in d.ChildNodes)
                                    {
                                        o.Properties.Add(e.ReadTag("name"), e.ReadTag("value"));
                                    }
                                    break;
                                case "image":
                                    string cp = d.ReadTag("trans", "FFFFFF");
                                    if (cp.Length == 6 && !cp.StartsWith("#")) { cp = "#" + cp; }
                                    Color t = ColorTranslator.FromHtml(cp);
                                    if (d.Attributes["trans"] != null)
                                    {
                                        o.Images.Add(new Image() { Source = d.ReadTag("source"), TransColor = t, UseTransColor = true });
                                    }
                                    else
                                    {
                                        o.Images.Add(new Image() { Source = d.ReadTag("source"), TransColor = t, UseTransColor = false });
                                    }
                                    break;
                            }
                        }
                    }
                    r.Add(o);
                }
            }
            map.ObjectGroups.Add(r);
        }
        static void ReadTileset(XmlNode node, ref Map map, string base_path)
        {
            TileSet r    = new TileSet();
            r.FirstGid   = node.ReadInt("firstgid");
            r.Source     = node.ReadTag("source");
            r.Name       = node.ReadTag("name");
            r.TileWidth  = node.ReadInt("tilewidth");
            r.TileHeight = node.ReadInt("tileheight");
            r.Spacing    = node.ReadInt("spacing");
            r.Margin     = node.ReadInt("margin");

            Console.Out.WriteLine (r.Source);

            if (r.Source != "") {

                String filename = Path.Combine (base_path, r.Source);

                Console.Out.WriteLine (r.Source);

                try {

                XmlDocument extTileset = new XmlDocument ();
                extTileset.Load (File.OpenRead (filename));
                foreach (XmlNode extNode in extTileset.ChildNodes) {

                    if (extNode.Name == "tileset")
                        node = extNode;
                }

                r.Name       = node.ReadTag("name");
                r.TileWidth  = node.ReadInt("tilewidth");
                r.TileHeight = node.ReadInt("tileheight");
                r.Spacing    = node.ReadInt("spacing");
                r.Margin     = node.ReadInt("margin");

                FileInfo fi = new FileInfo (filename);
                base_path = fi.DirectoryName;

                } catch (Exception e) {
                    Console.Out.WriteLine (e.Message);
                    return;
                }
            }

            if (node.HasChildNodes)
            {
                foreach (XmlNode child in node.ChildNodes)
                {

                    if (child.Name == "image") {
                        string c = child.ReadTag ("trans", "FFFFFF");
                        if (c.Length == 6 && !c.StartsWith ("#")) {
                            c = "#" + c;
                        }
                        Color t = ColorTranslator.FromHtml (c);

                        if (child.Attributes ["trans"] != null) {
                            r.Images.Add (new Image () {
                                Source = child.ReadTag ("source"),
                                TransColor = t,
                                UseTransColor = true
                            });
                        } else {
                            r.Images.Add (new Image () {
                                Source = child.ReadTag ("source"),
                                TransColor = t,
                                UseTransColor = false
                            });
                        }
                    } else if (child.Name == "tile") {
                        int id = child.ReadInt ("id");
                        Properties tileprops = new Properties();
                        XmlNode data = child.FirstChild; // Should be a properties tag.
                        foreach (XmlNode property in data.ChildNodes) {
                            tileprops.Add (property.ReadTag ("name"), property.ReadTag ("value"));
                        }
                        r.TileProperties.Add (id, tileprops);
                    }
                }
            }

            //r.ReadBitmaps(base_path);

            map.TileSets.Add(r);
        }
        static void ReadLayer(XmlNode node, ref Map map)
        {
            Layer r = new Layer(node.ReadInt("width"), node.ReadInt("height"));
            r.Name = node.ReadTag("name");
            r.X = node.ReadInt("x");
            r.Y = node.ReadInt("y");
            r.Opacity = node.ReadDouble("opacity", 1);
            r.Visible = node.ReadInt("visible") == 1;
            if(node.HasChildNodes)
            {
                XmlNode data = node.FirstChild;
                foreach (XmlNode child in node.ChildNodes) {
                    if (child.Name == "data") {
                        data = child;
                    }
                    if (child.Name == "properties") {
                        foreach (XmlNode prop in child.ChildNodes) {
                            r.Properties.Add (prop.ReadTag ("name"), prop.ReadTag ("value"));
                        }
                    }
                }

                string dataVal = data.InnerText.Trim('\n', ' ');
                string encoding = data.ReadTag("encoding");
                string compression = data.ReadTag("compression");

                byte[] dataToParse = new byte[0];
                byte[] dataDecompressed = new byte[0];
                if (encoding == "base64")
                {
                    dataToParse = Convert.FromBase64String(dataVal);
                }
                else if(encoding == "csv")
                {
                    dataToParse = Encoding.Unicode.GetBytes(dataVal.Replace(',', ' ').Replace("\n", ""));
                }

                if (compression == "gzip") {
                    dataDecompressed = GZip.Decompress (dataToParse);
                } else if (compression == "zlib") {
                    dataDecompressed = GZip.DecompressZlib (dataToParse);
                } else {
                    dataDecompressed = dataToParse;
                }

                BinaryReader br = new BinaryReader (new MemoryStream (dataDecompressed));
                /*using ()
                {*/

                    for (int y = 0; y < r.Height; y++)
                    {
                        for (int x = 0; x < r.Width; x++)
                        {

                            int v = br.ReadInt32();

                            r.Data[y,x] = (v&0xFFF)+1; //Why the +1? Investigate.
                            //Throwing away high bits to suvive rotated tiles.
                        }
                    }

                map.Layers.Add(r);

            }
        }