Beispiel #1
0
        /// <summary>
        ///     Reads a generic Pokémon container from a Stream.
        ///     Those containers are the ones that starts with "GR", "MM", "AD" and so on...
        /// </summary>
        /// <param name="data">Stream with container data</param>
        /// <returns></returns>
        public static OContainer load(Stream data)
        {
            BinaryReader input  = new BinaryReader(data);
            OContainer   output = new OContainer();

            IOUtils.readString(input, 0, 2); //Magic
            ushort sectionCount = input.ReadUInt16();

            for (int i = 0; i < sectionCount; i++)
            {
                OContainer.fileEntry entry = new OContainer.fileEntry();

                data.Seek(4 + (i * 4), SeekOrigin.Begin);
                uint startOffset = input.ReadUInt32();
                uint endOffset   = input.ReadUInt32();
                uint length      = endOffset - startOffset;

                data.Seek(startOffset, SeekOrigin.Begin);
                byte[] buffer = new byte[length];
                input.Read(buffer, 0, (int)length);
                entry.data = buffer;

                output.content.Add(entry);
            }

            data.Close();

            return(output);
        }
        /// <summary>
        ///     Reads a generic Pokémon container from a Stream.
        ///     Those containers are the ones that starts with "GR", "MM", "AD" and so on...
        /// </summary>
        /// <param name="data">Stream with container data</param>
        /// <returns></returns>
        public static OContainer load(Stream data)
        {
            BinaryReader input = new BinaryReader(data);
            OContainer output = new OContainer();

            IOUtils.readString(input, 0, 2); //Magic
            ushort sectionCount = input.ReadUInt16();
            for (int i = 0; i < sectionCount; i++)
            {
                OContainer.fileEntry entry = new OContainer.fileEntry();

                data.Seek(4 + (i * 4), SeekOrigin.Begin);
                uint startOffset = input.ReadUInt32();
                uint endOffset = input.ReadUInt32();
                uint length = endOffset - startOffset;

                data.Seek(startOffset, SeekOrigin.Begin);
                byte[] buffer = new byte[length];
                input.Read(buffer, 0, (int)length);
                entry.data = buffer;

                output.content.Add(entry);
            }

            data.Close();

            return output;
        }
Beispiel #3
0
        /// <summary>
        ///     Reads a GARC archive.
        /// </summary>
        /// <param name="data">Stream of the data</param>
        /// <returns>The container data</returns>
        public static OContainer load(Stream data)
        {
            OContainer   output = new OContainer();
            BinaryReader input  = new BinaryReader(data);

            output.data = data;

            string garcMagic        = IOUtils.readStringWithLength(input, 4);
            uint   garcHeaderLength = input.ReadUInt32();
            ushort endian           = input.ReadUInt16();

            input.ReadUInt16(); //0x400
            uint sectionCount       = input.ReadUInt32();
            uint dataOffset         = input.ReadUInt32();
            uint decompressedLength = input.ReadUInt32();
            uint compressedLength   = input.ReadUInt32();

            //File Allocation Table Offsets
            string fatoMagic        = IOUtils.readStringWithLength(input, 4);
            uint   fatoHeaderLength = input.ReadUInt32();
            ushort fatoEntries      = input.ReadUInt16();

            input.ReadUInt16();                             //0xffff = Padding?
            data.Seek(fatoEntries * 4, SeekOrigin.Current); //We don't need this

            string fatbMagic        = IOUtils.readStringWithLength(input, 4);
            uint   fatbHeaderLength = input.ReadUInt32();
            uint   entries          = input.ReadUInt32();

            long baseOffset = data.Position;

            for (int i = 0; i < entries; i++)
            {
                data.Seek(baseOffset + i * 0x10, SeekOrigin.Begin);

                uint flags       = input.ReadUInt32();
                uint startOffset = input.ReadUInt32();
                uint endOffset   = input.ReadUInt32();
                uint length      = input.ReadUInt32();

                input.BaseStream.Seek(startOffset + dataOffset, SeekOrigin.Begin);
                byte[] buffer = new byte[Math.Min(0x10, length)];
                input.Read(buffer, 0, buffer.Length);

                bool   isCompressed = buffer.Length > 0 ? buffer[0] == 0x11 : false;
                string extension    = FileIO.getExtension(buffer, isCompressed ? 5 : 0);
                string name         = string.Format("file_{0:D5}{1}", i, extension);

                //And add the file to the container list
                OContainer.fileEntry entry = new OContainer.fileEntry();
                entry.name         = name;
                entry.loadFromDisk = true;
                entry.fileOffset   = startOffset + dataOffset;
                entry.fileLength   = length;
                output.content.Add(entry);
            }

            return(output);
        }
        /// <summary>
        ///     Reads a DARC archive.
        /// </summary>
        /// <param name="data">Stream of the data</param>
        /// <returns>The container data</returns>
        public static OContainer load(Stream data)
        {
            OContainer output = new OContainer();
            BinaryReader input = new BinaryReader(data);

            string darcMagic = IOUtils.readStringWithLength(input, 4);
            ushort endian = input.ReadUInt16();
            ushort headerLength = input.ReadUInt16();
            uint version = input.ReadUInt32();
            uint fileSize = input.ReadUInt32();
            uint tableOffset = input.ReadUInt32();
            uint tableLength = input.ReadUInt32();
            uint dataOffset = input.ReadUInt32();

            data.Seek(tableOffset, SeekOrigin.Begin);
            fileEntry root = getEntry(input);
            int baseOffset = (int)data.Position;
            int namesOffset = (int)(tableOffset + root.length * 0xc);

            string currDir = null;
            for (int i = 0; i < root.length - 1; i++)
            {
                data.Seek(baseOffset + i * 0xc, SeekOrigin.Begin);

                fileEntry entry = getEntry(input);

                if ((entry.flags & 1) > 0)
                {
                    //Folder
                    int index = i;
                    currDir = null;
                    for (;;)
                    {
                        uint parentIndex = entry.offset;
                        currDir = getName(input, entry.nameOffset + namesOffset) + "/" + currDir;
                        if (parentIndex == 0 || parentIndex == index) break;
                        data.Seek(baseOffset + parentIndex * 0xc, SeekOrigin.Begin);
                        entry = getEntry(input);
                        index = (int)parentIndex;
                    }

                    continue;
                }

                data.Seek(entry.offset, SeekOrigin.Begin);
                byte[] buffer = new byte[entry.length];
                data.Read(buffer, 0, buffer.Length);

                OContainer.fileEntry file = new OContainer.fileEntry();
                file.name = currDir + getName(input, entry.nameOffset + namesOffset);
                file.data = buffer;

                output.content.Add(file);
            }

            data.Close();
            return output;
        }
        /// <summary>
        ///     Reads a GARC archive.
        /// </summary>
        /// <param name="data">Stream of the data</param>
        /// <returns>The container data</returns>
        public static OContainer load(Stream data)
        {
            OContainer output = new OContainer();
            BinaryReader input = new BinaryReader(data);

            output.data = data;

            string garcMagic = IOUtils.readStringWithLength(input, 4);
            uint garcHeaderLength = input.ReadUInt32();
            ushort endian = input.ReadUInt16();
            input.ReadUInt16(); //0x400
            uint sectionCount = input.ReadUInt32();
            uint dataOffset = input.ReadUInt32();
            uint decompressedLength = input.ReadUInt32();
            uint compressedLength = input.ReadUInt32();

            //File Allocation Table Offsets
            string fatoMagic = IOUtils.readStringWithLength(input, 4);
            uint fatoHeaderLength = input.ReadUInt32();
            ushort fatoEntries = input.ReadUInt16();
            input.ReadUInt16(); //0xffff = Padding?
            data.Seek(fatoEntries * 4, SeekOrigin.Current); //We don't need this

            string fatbMagic = IOUtils.readStringWithLength(input, 4);
            uint fatbHeaderLength = input.ReadUInt32();
            uint entries = input.ReadUInt32();

            long baseOffset = data.Position;

            for (int i = 0; i < entries; i++)
            {
                data.Seek(baseOffset + i * 0x10, SeekOrigin.Begin);

                uint flags = input.ReadUInt32();
                uint startOffset = input.ReadUInt32();
                uint endOffset = input.ReadUInt32();
                uint length = input.ReadUInt32();

                input.BaseStream.Seek(startOffset + dataOffset, SeekOrigin.Begin);
                byte[] buffer = new byte[Math.Min(0x10, length)];
                input.Read(buffer, 0, buffer.Length);

                bool isCompressed = buffer.Length > 0 ? buffer[0] == 0x11 : false;
                string extension = FileIO.getExtension(buffer, isCompressed ? 5 : 0);
                string name = string.Format("file_{0:D5}{1}", i, extension);

                //And add the file to the container list
                OContainer.fileEntry entry = new OContainer.fileEntry();
                entry.name = name;
                entry.loadFromDisk = true;
                entry.fileOffset = startOffset + dataOffset;
                entry.fileLength = length;
                output.content.Add(entry);
            }

            return output;
        }
Beispiel #6
0
        /// <summary>
        ///     Reads a SARC archive.
        /// </summary>
        /// <param name="data">Stream of the data</param>
        /// <returns>The container data</returns>
        public static OContainer load(Stream data)
        {
            OContainer   output = new OContainer();
            BinaryReader input  = new BinaryReader(data);

            string sarcMagic        = IOUtils.readStringWithLength(input, 4);
            ushort sarcHeaderLength = input.ReadUInt16();
            ushort endian           = input.ReadUInt16();
            uint   fileLength       = input.ReadUInt32();
            uint   dataOffset       = input.ReadUInt32();
            uint   dataPadding      = input.ReadUInt32();

            string sfatMagic        = IOUtils.readStringWithLength(input, 4);
            ushort sfatHeaderLength = input.ReadUInt16();
            ushort entries          = input.ReadUInt16();
            uint   hashMultiplier   = input.ReadUInt32();
            int    sfntOffset       = 0x20 + entries * 0x10 + 8;

            for (int i = 0; i < entries; i++)
            {
                data.Seek(0x20 + i * 0x10, SeekOrigin.Begin);

                uint nameHash   = input.ReadUInt32();
                uint nameOffset = (input.ReadUInt32() & 0xffffff) << 2;
                uint offset     = input.ReadUInt32();
                uint length     = input.ReadUInt32() - offset;

                string name = IOUtils.readString(input, (uint)(sfntOffset + nameOffset));
                data.Seek(offset + dataOffset, SeekOrigin.Begin);
                byte[] buffer = new byte[length];
                data.Read(buffer, 0, buffer.Length);
                if (name == "")
                {
                    name = string.Format("file_{0:D5}{1}", i, FileIO.getExtension(buffer));
                }

                OContainer.fileEntry entry = new OContainer.fileEntry();
                entry.name = name;
                entry.data = buffer;
                output.content.Add(entry);
            }

            data.Close();
            return(output);
        }
Beispiel #7
0
        /// <summary>
        ///     Reads FPT0 containers from Dragon Quest VII.
        /// </summary>
        /// <param name="data">Stream with container data</param>
        /// <returns></returns>
        public static OContainer load(Stream data)
        {
            BinaryReader input  = new BinaryReader(data);
            OContainer   output = new OContainer();

            data.Seek(8, SeekOrigin.Begin);
            uint entries     = input.ReadUInt32();
            uint baseAddress = 0x10 + (entries * 0x20) + 0x80;

            input.ReadUInt32();

            List <sectionEntry> files = new List <sectionEntry>();

            for (int i = 0; i < entries; i++)
            {
                sectionEntry entry = new sectionEntry();

                entry.name = IOUtils.readString(input, (uint)(0x10 + (i * 0x20)));
                data.Seek(0x20 + (i * 0x20), SeekOrigin.Begin);
                input.ReadUInt32(); //Memory address?
                entry.offset = input.ReadUInt32() + baseAddress;
                entry.length = input.ReadUInt32();
                input.ReadUInt32(); //Padding?

                files.Add(entry);
            }

            foreach (sectionEntry file in files)
            {
                OContainer.fileEntry entry = new OContainer.fileEntry();

                data.Seek(file.offset, SeekOrigin.Begin);
                byte[] buffer = new byte[file.length];
                input.Read(buffer, 0, buffer.Length);
                entry.data = buffer;
                entry.name = file.name;

                output.content.Add(entry);
            }

            data.Close();

            return(output);
        }
        /// <summary>
        ///     Reads FPT0 containers from Dragon Quest VII.
        /// </summary>
        /// <param name="data">Stream with container data</param>
        /// <returns></returns>
        public static OContainer load(Stream data)
        {
            BinaryReader input = new BinaryReader(data);
            OContainer output = new OContainer();

            data.Seek(8, SeekOrigin.Begin);
            uint entries = input.ReadUInt32();
            uint baseAddress = 0x10 + (entries * 0x20) + 0x80;
            input.ReadUInt32();

            List<sectionEntry> files = new List<sectionEntry>();
            for (int i = 0; i < entries; i++)
            {
                sectionEntry entry = new sectionEntry();

                entry.name = IOUtils.readString(input, (uint)(0x10 + (i * 0x20)));
                data.Seek(0x20 + (i * 0x20), SeekOrigin.Begin);
                input.ReadUInt32(); //Memory address?
                entry.offset = input.ReadUInt32() + baseAddress;
                entry.length = input.ReadUInt32();
                input.ReadUInt32(); //Padding?

                files.Add(entry);
            }

            foreach (sectionEntry file in files)
            {
                OContainer.fileEntry entry = new OContainer.fileEntry();

                data.Seek(file.offset, SeekOrigin.Begin);
                byte[] buffer = new byte[file.length];
                input.Read(buffer, 0, buffer.Length);
                entry.data = buffer;
                entry.name = file.name;

                output.content.Add(entry);
            }

            data.Close();

            return output;
        }
        /// <summary>
        ///     Reads a SARC archive.
        /// </summary>
        /// <param name="data">Stream of the data</param>
        /// <returns>The container data</returns>
        public static OContainer load(Stream data)
        {
            OContainer output = new OContainer();
            BinaryReader input = new BinaryReader(data);

            string sarcMagic = IOUtils.readStringWithLength(input, 4);
            ushort sarcHeaderLength = input.ReadUInt16();
            ushort endian = input.ReadUInt16();
            uint fileLength = input.ReadUInt32();
            uint dataOffset = input.ReadUInt32();
            uint dataPadding = input.ReadUInt32();

            string sfatMagic = IOUtils.readStringWithLength(input, 4);
            ushort sfatHeaderLength = input.ReadUInt16();
            ushort entries = input.ReadUInt16();
            uint hashMultiplier = input.ReadUInt32();
            int sfntOffset = 0x20 + entries * 0x10 + 8;

            for (int i = 0; i < entries; i++)
            {
                data.Seek(0x20 + i * 0x10, SeekOrigin.Begin);

                uint nameHash = input.ReadUInt32();
                uint nameOffset = (input.ReadUInt32() & 0xffffff) << 2;
                uint offset = input.ReadUInt32();
                uint length = input.ReadUInt32() - offset;

                string name = IOUtils.readString(input, (uint)(sfntOffset + nameOffset));
                data.Seek(offset + dataOffset, SeekOrigin.Begin);
                byte[] buffer = new byte[length];
                data.Read(buffer, 0, buffer.Length);
                if (name == "") name = string.Format("file_{0:D5}{1}", i, FileIO.getExtension(buffer));

                OContainer.fileEntry entry = new OContainer.fileEntry();
                entry.name = name;
                entry.data = buffer;
                output.content.Add(entry);
            }

            data.Close();
            return output;
        }
Beispiel #10
0
        /// <summary>
        ///     Reads a generic Pokémon container from a Stream.
        ///     Those containers are the ones that starts with "GR", "MM", "AD" and so on...
        /// </summary>
        /// <param name="data">Stream with container data</param>
        /// <returns></returns>
        public static OContainer load(Stream data)
        {
            BinaryReader input  = new BinaryReader(data);;
            OContainer   output = null;

            string magic        = IOUtils.readString(input, 0, 2); //Magic
            ushort sectionCount = input.ReadUInt16();

            output = new OContainer();

            for (int i = 0; i < sectionCount; i++)
            {
                OContainer.fileEntry entry = new OContainer.fileEntry();

                data.Seek(4 + (i * 4), SeekOrigin.Begin);
                uint startOffset = input.ReadUInt32();
                uint endOffset   = input.ReadUInt32();
                uint length      = endOffset - startOffset;

                data.Seek(startOffset, SeekOrigin.Begin);
                byte[] buffer = new byte[length];
                input.Read(buffer, 0, (int)length);

                bool   isCompressed = buffer.Length > 0 ? buffer[0] == 0x11 : false;
                string extension    = FileIO.getExtension(buffer, isCompressed ? 5 : 0);
                string name         = string.Format("file_{0:D5}{1}", i, extension);

                entry.data = buffer;
                entry.name = name;

                output.content.Add(entry);
            }

            data.Close();

            return(output);
        }
        /// <summary>
        ///     Reads the Model PACKage from Dragon Quest VII.
        /// </summary>
        /// <param name="data">Stream of the data</param>
        /// <returns></returns>
        public static OContainer load(Stream data)
        {
            BinaryReader input = new BinaryReader(data);
            OContainer output = new OContainer();

            List<sectionEntry> mainSection = getSection(input);

            //World nodes section
            data.Seek(mainSection[0].offset, SeekOrigin.Begin);
            List<node> nodes = new List<node>();
            List<sectionEntry> worldNodesSection = getSection(input);
            foreach (sectionEntry entry in worldNodesSection)
            {
                data.Seek(entry.offset, SeekOrigin.Begin);

                node n = new node();

                //Geometry node
                input.ReadUInt32(); //GNOD magic number
                input.ReadUInt32();
                input.ReadUInt32();
                n.parentId = input.ReadInt32();
                n.name = IOUtils.readString(input, (uint)data.Position);

                data.Seek(entry.offset + 0x20, SeekOrigin.Begin);
                n.transform = new RenderBase.OMatrix();
                RenderBase.OVector4 t = new RenderBase.OVector4(input.ReadSingle(), input.ReadSingle(), input.ReadSingle(), input.ReadSingle());
                RenderBase.OVector4 r = new RenderBase.OVector4(input.ReadSingle(), input.ReadSingle(), input.ReadSingle(), input.ReadSingle());
                RenderBase.OVector4 s = new RenderBase.OVector4(input.ReadSingle(), input.ReadSingle(), input.ReadSingle(), input.ReadSingle());
                n.transform *= RenderBase.OMatrix.scale(new RenderBase.OVector3(s.x, s.y, s.z));
                n.transform *= RenderBase.OMatrix.rotateX(r.x);
                n.transform *= RenderBase.OMatrix.rotateY(r.y);
                n.transform *= RenderBase.OMatrix.rotateZ(r.z);
                n.transform *= RenderBase.OMatrix.translate(new RenderBase.OVector3(t.x, t.y, t.z));

                nodes.Add(n);
            }

            RenderBase.OMatrix[] nodesTransform = new RenderBase.OMatrix[nodes.Count];
            for (int i = 0; i < nodes.Count; i++)
            {
                RenderBase.OMatrix transform = new RenderBase.OMatrix();
                transformNode(nodes, i, ref transform);
                nodesTransform[i] = transform;
            }

            //Models section
            data.Seek(mainSection[1].offset, SeekOrigin.Begin);
            List<sectionEntry> modelsSection = getSection(input);
            foreach (sectionEntry entry in modelsSection)
            {
                data.Seek(entry.offset, SeekOrigin.Begin);
                
                //Field Data section
                /*
                 * Usually have 3 entries.
                 * 1st entry: Model CGFX
                 * 2nd entry: Unknow CGFX, possibly animations
                 * 3rd entry: Another FieldData section, possibly child object
                 */

                List<sectionEntry> fieldDataSection = getSection(input);
                data.Seek(fieldDataSection[0].offset, SeekOrigin.Begin);
                uint length = fieldDataSection[0].length;
                while ((length & 0x7f) != 0) length++; //Align
                byte[] buffer = new byte[length];
                input.Read(buffer, 0, buffer.Length);

                OContainer.fileEntry file = new OContainer.fileEntry();
                file.name = CGFX.getName(new MemoryStream(buffer)) + ".bcmdl";
                file.data = buffer;

                output.content.Add(file);
            }

            //FILE section
            data.Seek(mainSection[2].offset, SeekOrigin.Begin);
            //TODO

            //Collision section
            data.Seek(mainSection[3].offset, SeekOrigin.Begin);
            //TODO

            //PARM(???) section
            data.Seek(mainSection[4].offset, SeekOrigin.Begin);
            //TODO

            //Textures CGFX
            data.Seek(mainSection[5].offset, SeekOrigin.Begin);
            byte[] texBuffer = new byte[mainSection[5].length];
            input.Read(texBuffer, 0, texBuffer.Length);

            OContainer.fileEntry texFile = new OContainer.fileEntry();
            texFile.name = "textures.bctex";
            texFile.data = texBuffer;

            output.content.Add(texFile);

            data.Close();

            return output;
        }
Beispiel #12
0
        /// <summary>
        ///     Reads a DARC archive.
        /// </summary>
        /// <param name="data">Stream of the data</param>
        /// <returns>The container data</returns>
        public static OContainer load(Stream data)
        {
            OContainer   output = new OContainer();
            BinaryReader input  = new BinaryReader(data);

            string darcMagic    = IOUtils.readStringWithLength(input, 4);
            ushort endian       = input.ReadUInt16();
            ushort headerLength = input.ReadUInt16();
            uint   version      = input.ReadUInt32();
            uint   fileSize     = input.ReadUInt32();
            uint   tableOffset  = input.ReadUInt32();
            uint   tableLength  = input.ReadUInt32();
            uint   dataOffset   = input.ReadUInt32();

            data.Seek(tableOffset, SeekOrigin.Begin);
            fileEntry root        = getEntry(input);
            int       baseOffset  = (int)data.Position;
            int       namesOffset = (int)(tableOffset + root.length * 0xc);

            string currDir = null;

            for (int i = 0; i < root.length - 1; i++)
            {
                data.Seek(baseOffset + i * 0xc, SeekOrigin.Begin);

                fileEntry entry = getEntry(input);

                if ((entry.flags & 1) > 0)
                {
                    //Folder
                    int index = i;
                    currDir = null;
                    for (;;)
                    {
                        uint parentIndex = entry.offset;
                        currDir = getName(input, entry.nameOffset + namesOffset) + "/" + currDir;
                        if (parentIndex == 0 || parentIndex == index)
                        {
                            break;
                        }
                        data.Seek(baseOffset + parentIndex * 0xc, SeekOrigin.Begin);
                        entry = getEntry(input);
                        index = (int)parentIndex;
                    }

                    continue;
                }

                data.Seek(entry.offset, SeekOrigin.Begin);
                byte[] buffer = new byte[entry.length];
                data.Read(buffer, 0, buffer.Length);

                OContainer.fileEntry file = new OContainer.fileEntry();
                file.name = currDir + getName(input, entry.nameOffset + namesOffset);
                file.data = buffer;

                output.content.Add(file);
            }

            data.Close();
            return(output);
        }
Beispiel #13
0
        /// <summary>
        ///     Reads a GARC archive.
        /// </summary>
        /// <param name="data">Stream of the data</param>
        /// <returns>The container data</returns>
        public static OContainer load(Stream data)
        {
            OContainer   output = new OContainer();
            BinaryReader input  = new BinaryReader(data);

            output.data = data;

            string garcMagic          = IOUtils.readStringWithLength(input, 4);
            uint   garcLength         = input.ReadUInt32();
            ushort endian             = input.ReadUInt16();
            ushort version            = input.ReadUInt16(); //0x400
            uint   sectionCount       = input.ReadUInt32();
            uint   dataOffset         = input.ReadUInt32();
            uint   decompressedLength = input.ReadUInt32();
            uint   compressedLength   = input.ReadUInt32();

            data.Seek(garcLength, SeekOrigin.Begin); //This is just the header "GARC" blk len, not the entire file

            //File Allocation Table Offsets
            long   fatoPosition = data.Position;
            string fatoMagic    = IOUtils.readStringWithLength(input, 4);
            uint   fatoLength   = input.ReadUInt32();
            ushort fatoEntries  = input.ReadUInt16();

            input.ReadUInt16(); //0xffff = Padding?

            long fatbPosition = fatoPosition + fatoLength;

            for (int i = 0; i < fatoEntries; i++)
            {
                data.Seek(fatoPosition + 0xc + i * 4, SeekOrigin.Begin);
                data.Seek(input.ReadUInt32() + fatbPosition + 0xc, SeekOrigin.Begin);

                uint flags = input.ReadUInt32();

                string folder = string.Empty;

                if (flags != 1)
                {
                    folder = string.Format("folder_{0:D5}/", i);
                }

                for (int bit = 0; bit < 32; bit++)
                {
                    if ((flags & (1 << bit)) > 0)
                    {
                        uint startOffset = input.ReadUInt32();
                        uint endOffset   = input.ReadUInt32();
                        uint length      = input.ReadUInt32();

                        long position = data.Position;

                        input.BaseStream.Seek(startOffset + dataOffset, SeekOrigin.Begin);

                        byte[] buffer = new byte[length];
                        input.Read(buffer, 0, buffer.Length);

                        bool   isCompressed = buffer.Length > 0 ? buffer[0] == 0x11 : false;
                        string extension    = FileIO.getExtension(buffer, isCompressed ? 5 : 0);
                        string name         = folder + string.Format("file_{0:D5}{1}", flags == 1 ? i : bit, extension);

                        //And add the file to the container list
                        OContainer.fileEntry entry = new OContainer.fileEntry();
                        entry.name            = name;
                        entry.loadFromDisk    = true;
                        entry.fileOffset      = startOffset + dataOffset;
                        entry.fileLength      = length;
                        entry.doDecompression = isCompressed;
                        output.content.Add(entry);

                        input.BaseStream.Seek(position, SeekOrigin.Begin);
                    }
                }
            }

            return(output);
        }
        /// <summary>
        ///     Reads the Model PACKage from Dragon Quest VII.
        /// </summary>
        /// <param name="data">Stream of the data</param>
        /// <returns></returns>
        public static OContainer load(Stream data)
        {
            BinaryReader input  = new BinaryReader(data);
            OContainer   output = new OContainer();

            List <sectionEntry> mainSection = getSection(input);

            //World nodes section
            data.Seek(mainSection[0].offset, SeekOrigin.Begin);
            List <node>         nodes             = new List <node>();
            List <sectionEntry> worldNodesSection = getSection(input);

            foreach (sectionEntry entry in worldNodesSection)
            {
                data.Seek(entry.offset, SeekOrigin.Begin);

                node n = new node();

                //Geometry node
                input.ReadUInt32(); //GNOD magic number
                input.ReadUInt32();
                input.ReadUInt32();
                n.parentId = input.ReadInt32();
                n.name     = IOUtils.readString(input, (uint)data.Position);

                data.Seek(entry.offset + 0x20, SeekOrigin.Begin);
                n.transform = new RenderBase.OMatrix();
                RenderBase.OVector4 t = new RenderBase.OVector4(input.ReadSingle(), input.ReadSingle(), input.ReadSingle(), input.ReadSingle());
                RenderBase.OVector4 r = new RenderBase.OVector4(input.ReadSingle(), input.ReadSingle(), input.ReadSingle(), input.ReadSingle());
                RenderBase.OVector4 s = new RenderBase.OVector4(input.ReadSingle(), input.ReadSingle(), input.ReadSingle(), input.ReadSingle());
                n.transform *= RenderBase.OMatrix.scale(new RenderBase.OVector3(s.x, s.y, s.z));
                n.transform *= RenderBase.OMatrix.rotateX(r.x);
                n.transform *= RenderBase.OMatrix.rotateY(r.y);
                n.transform *= RenderBase.OMatrix.rotateZ(r.z);
                n.transform *= RenderBase.OMatrix.translate(new RenderBase.OVector3(t.x, t.y, t.z));

                nodes.Add(n);
            }

            RenderBase.OMatrix[] nodesTransform = new RenderBase.OMatrix[nodes.Count];
            for (int i = 0; i < nodes.Count; i++)
            {
                RenderBase.OMatrix transform = new RenderBase.OMatrix();
                transformNode(nodes, i, ref transform);
                nodesTransform[i] = transform;
            }

            //Models section
            data.Seek(mainSection[1].offset, SeekOrigin.Begin);
            List <sectionEntry> modelsSection = getSection(input);

            foreach (sectionEntry entry in modelsSection)
            {
                data.Seek(entry.offset, SeekOrigin.Begin);

                //Field Data section

                /*
                 * Usually have 3 entries.
                 * 1st entry: Model CGFX
                 * 2nd entry: Unknow CGFX, possibly animations
                 * 3rd entry: Another FieldData section, possibly child object
                 */

                List <sectionEntry> fieldDataSection = getSection(input);
                data.Seek(fieldDataSection[0].offset, SeekOrigin.Begin);
                uint length = fieldDataSection[0].length;
                while ((length & 0x7f) != 0)
                {
                    length++;                          //Align
                }
                byte[] buffer = new byte[length];
                input.Read(buffer, 0, buffer.Length);

                OContainer.fileEntry file = new OContainer.fileEntry();
                file.name = CGFX.getName(new MemoryStream(buffer)) + ".bcmdl";
                file.data = buffer;

                output.content.Add(file);
            }

            //FILE section
            data.Seek(mainSection[2].offset, SeekOrigin.Begin);
            //TODO

            //Collision section
            data.Seek(mainSection[3].offset, SeekOrigin.Begin);
            //TODO

            //PARM(???) section
            data.Seek(mainSection[4].offset, SeekOrigin.Begin);
            //TODO

            //Textures CGFX
            data.Seek(mainSection[5].offset, SeekOrigin.Begin);
            byte[] texBuffer = new byte[mainSection[5].length];
            input.Read(texBuffer, 0, texBuffer.Length);

            OContainer.fileEntry texFile = new OContainer.fileEntry();
            texFile.name = "textures.bctex";
            texFile.data = texBuffer;

            output.content.Add(texFile);

            data.Close();

            return(output);
        }