public SkeletonData ReadSkeletonData(TextReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader cannot be null.");
            }

            SkeletonData skeletonData = new SkeletonData();

            var root = Json.Deserialize(reader) as Dictionary <String, Object>;

            if (root == null)
            {
                throw new Exception("Invalid JSON.");
            }

            // Bones.
            foreach (Dictionary <String, Object> boneMap in (List <Object>)root["bones"])
            {
                BoneData parent = null;
                if (boneMap.ContainsKey("parent"))
                {
                    parent = skeletonData.FindBone((String)boneMap["parent"]);
                    if (parent == null)
                    {
                        throw new Exception("Parent bone not found: " + boneMap["parent"]);
                    }
                }
                BoneData boneData = new BoneData((String)boneMap["name"], parent);
                boneData.Length          = GetFloat(boneMap, "length", 0) * Scale;
                boneData.X               = GetFloat(boneMap, "x", 0) * Scale;
                boneData.Y               = GetFloat(boneMap, "y", 0) * Scale;
                boneData.Rotation        = GetFloat(boneMap, "rotation", 0);
                boneData.ScaleX          = GetFloat(boneMap, "scaleX", 1);
                boneData.ScaleY          = GetFloat(boneMap, "scaleY", 1);
                boneData.InheritScale    = GetBoolean(boneMap, "inheritScale", true);
                boneData.InheritRotation = GetBoolean(boneMap, "inheritRotation", true);
                skeletonData.AddBone(boneData);
            }

            // Slots.
            if (root.ContainsKey("slots"))
            {
                var slots = (List <Object>)root["slots"];
                foreach (Dictionary <String, Object> slotMap in (List <Object>)slots)
                {
                    String   slotName = (String)slotMap["name"];
                    String   boneName = (String)slotMap["bone"];
                    BoneData boneData = skeletonData.FindBone(boneName);
                    if (boneData == null)
                    {
                        throw new Exception("Slot bone not found: " + boneName);
                    }
                    SlotData slotData = new SlotData(slotName, boneData);

                    if (slotMap.ContainsKey("color"))
                    {
                        String color = (String)slotMap["color"];
                        slotData.R = ToColor(color, 0);
                        slotData.G = ToColor(color, 1);
                        slotData.B = ToColor(color, 2);
                        slotData.A = ToColor(color, 3);
                    }

                    if (slotMap.ContainsKey("attachment"))
                    {
                        slotData.AttachmentName = (String)slotMap["attachment"];
                    }

                    skeletonData.AddSlot(slotData);
                }
            }

            // Skins.
            if (root.ContainsKey("skins"))
            {
                var skinMap = (Dictionary <String, Object>)root["skins"];
                foreach (KeyValuePair <String, Object> entry in skinMap)
                {
                    Skin skin = new Skin(entry.Key);
                    foreach (KeyValuePair <String, Object> slotEntry in (Dictionary <String, Object>)entry.Value)
                    {
                        int slotIndex = skeletonData.FindSlotIndex(slotEntry.Key);
                        foreach (KeyValuePair <String, Object> attachmentEntry in ((Dictionary <String, Object>)slotEntry.Value))
                        {
                            Attachment attachment = ReadAttachment(skin, attachmentEntry.Key, (Dictionary <String, Object>)attachmentEntry.Value);
                            skin.AddAttachment(slotIndex, attachmentEntry.Key, attachment);
                        }
                    }
                    skeletonData.AddSkin(skin);
                    if (skin.Name == "default")
                    {
                        skeletonData.DefaultSkin = skin;
                    }
                }
            }


            // Animations.
            if (root.ContainsKey("animations"))
            {
                var animationMap = (Dictionary <String, Object>)root["animations"];
                foreach (KeyValuePair <String, Object> entry in animationMap)
                {
                    ReadAnimation(entry.Key, (Dictionary <String, Object>)entry.Value, skeletonData);
                }
            }

            skeletonData.Bones.TrimExcess();
            skeletonData.Slots.TrimExcess();
            skeletonData.Skins.TrimExcess();
            skeletonData.Animations.TrimExcess();
            return(skeletonData);
        }