public void Read(EndianBinaryReader er)
        {
            GrannyUtils.SubreadUInt64Pointer(
                er, ser => { this.Name = ser.ReadStringNT(); });

            this.Duration     = er.ReadSingle();
            this.TimeStep     = er.ReadSingle();
            this.Oversampling = er.ReadSingle();

            var trackGroupCount = er.ReadUInt32();

            GrannyUtils.SubreadUInt64Pointer(er, ser => {
                for (var i = 0; i < trackGroupCount; ++i)
                {
                    var trackGroup = new GrannyTrackGroup();
                    trackGroup.Read(ser);
                    this.TrackGroups.Add(trackGroup);
                }
            });
        }
        public void Read(EndianBinaryReader er)
        {
            // TODO: Make this offset-agnostic.
            // The reader passed into this method should have an offset of 0 at the
            // start of the granny_file_info object.
            Asserts.Equal(0, er.Position, "Expected to start reading at offset 0.");

            er.ReadUInt64(); // ArtToolInfo
            er.ReadUInt64(); // ExporterInfo

            GrannyUtils.SubreadUInt64Pointer(
                er, ser => { this.FromFileName = ser.ReadStringNT(); });

            var textureCount = er.ReadUInt32();

            GrannyUtils.SubreadUInt64Pointer(er, ser => { });

            var materialCount = er.ReadUInt32();

            GrannyUtils.SubreadUInt64Pointer(er, ser => { });

            var skeletonCount = er.ReadUInt32();

            GrannyUtils.SubreadUInt64Pointer(
                er,
                ser => {
                for (var i = 0; i < skeletonCount; ++i)
                {
                    GrannyUtils.SubreadUInt64Pointer(ser, sser => {
                        var skeleton = new GrannySkeleton();
                        skeleton.Read(sser);
                        this.SkeletonHeaderList.Add(skeleton);
                    });
                }
            });

            var vertexDataCount = er.ReadUInt32();

            GrannyUtils.SubreadUInt64Pointer(er, ser => { });

            var modelHeaderCount = er.ReadUInt32();

            GrannyUtils.SubreadUInt64Pointer(er, ser => { });

            var trackGroupHeaderCount = er.ReadUInt32();

            GrannyUtils.SubreadUInt64Pointer(
                er,
                ser => {
                for (var i = 0; i < trackGroupHeaderCount; ++i)
                {
                    GrannyUtils.SubreadUInt64Pointer(ser, sser => {
                        var trackGroup = new GrannyTrackGroup();
                        trackGroup.Read(ser);
                        this.TrackGroupHeaderList.Add(trackGroup);
                    });
                }
            });

            var animationHeaderCount = er.ReadUInt32();

            GrannyUtils.SubreadUInt64Pointer(
                er,
                ser => {
                for (var i = 0; i < animationHeaderCount; ++i)
                {
                    GrannyUtils.SubreadUInt64Pointer(ser, sser => {
                        var animation = new GrannyAnimation();
                        animation.Read(sser);
                        this.AnimationHeaderList.Add(animation);
                    });
                }
            });
        }