示例#1
0
        public static void AssignPositionsForMeta(IList <IResourceBlock> blocks, uint basePosition, out RpfResourcePageFlags pageFlags)
        {
            // find largest structure
            long largestBlockSize = 0;

            foreach (var block in blocks)
            {
                if (largestBlockSize < block.BlockLength)
                {
                    largestBlockSize = block.BlockLength;
                }
            }

            // find minimum page size
            long currentPageSize = 0x2000;

            while (currentPageSize < largestBlockSize)
            {
                currentPageSize *= 2;
            }

            long currentPageCount;
            long currentPosition;

            while (true)
            {
                currentPageCount = 0;
                currentPosition  = 0;

                // reset all positions
                foreach (var block in blocks)
                {
                    block.FilePosition = -1;
                }

                foreach (var block in blocks)
                {
                    if (block.FilePosition != -1)
                    {
                        throw new Exception("Block was already assigned a position!");
                    }

                    // check if new page is necessary...
                    // if yes, add a new page and align to it
                    long maxSpace = currentPageCount * currentPageSize - currentPosition;
                    if (maxSpace < (block.BlockLength + SKIP_SIZE))
                    {
                        currentPageCount++;
                        currentPosition = currentPageSize * (currentPageCount - 1);
                    }

                    // set position
                    block.FilePosition = basePosition + currentPosition;
                    currentPosition   += block.BlockLength; // + SKIP_SIZE; //is padding everywhere really necessary??

                    // align...
                    if ((currentPosition % ALIGN_SIZE) != 0)
                    {
                        currentPosition += (ALIGN_SIZE - (currentPosition % ALIGN_SIZE));
                    }
                }

                // break if everything fits...
                if (currentPageCount < 128)
                {
                    break;
                }

                currentPageSize *= 2;
            }

            pageFlags = new RpfResourcePageFlags(RpfResourceFileEntry.GetFlagsFromBlocks((uint)currentPageCount, (uint)currentPageSize, 0));
        }
        public static byte[] Build(ResourceFileBase fileBase, int version, bool compress = true)
        {
            fileBase.FilePagesInfo = new ResourcePagesInfo();

            IList <IResourceBlock> systemBlocks;
            IList <IResourceBlock> graphicBlocks;

            GetBlocks(fileBase, out systemBlocks, out graphicBlocks);

            int systemPageSize = BASE_SIZE;// *4;
            int systemPageCount;

            AssignPositions(systemBlocks, 0x50000000, ref systemPageSize, out systemPageCount);

            int graphicsPageSize = BASE_SIZE;
            int graphicsPageCount;

            AssignPositions(graphicBlocks, 0x60000000, ref graphicsPageSize, out graphicsPageCount);



            //fileBase.FilePagesInfo.SystemPagesCount = 0;
            //if (systemPageCount > 0)
            //    fileBase.FilePagesInfo.SystemPagesCount = 1; // (byte)systemPageCount; //1
            fileBase.FilePagesInfo.SystemPagesCount   = (byte)systemPageCount;
            fileBase.FilePagesInfo.GraphicsPagesCount = (byte)graphicsPageCount;



            var systemStream   = new MemoryStream();
            var graphicsStream = new MemoryStream();
            var resourceWriter = new ResourceDataWriter(systemStream, graphicsStream);

            resourceWriter.Position = 0x50000000;
            foreach (var block in systemBlocks)
            {
                resourceWriter.Position = block.FilePosition;

                var pos_before = resourceWriter.Position;
                block.Write(resourceWriter);
                var pos_after = resourceWriter.Position;

                if ((pos_after - pos_before) != block.BlockLength)
                {
                    throw new Exception("error in system length");
                }
            }

            resourceWriter.Position = 0x60000000;
            foreach (var block in graphicBlocks)
            {
                resourceWriter.Position = block.FilePosition;

                var pos_before = resourceWriter.Position;
                block.Write(resourceWriter);
                var pos_after = resourceWriter.Position;

                if ((pos_after - pos_before) != block.BlockLength)
                {
                    throw new Exception("error in graphics length");
                }
            }



            var sysDataSize = systemPageCount * systemPageSize;
            var sysData     = new byte[sysDataSize];

            systemStream.Flush();
            systemStream.Position = 0;
            systemStream.Read(sysData, 0, (int)systemStream.Length);


            var gfxDataSize = graphicsPageCount * graphicsPageSize;
            var gfxData     = new byte[gfxDataSize];

            graphicsStream.Flush();
            graphicsStream.Position = 0;
            graphicsStream.Read(gfxData, 0, (int)graphicsStream.Length);



            uint uv = (uint)version;
            uint sv = (uv >> 4) & 0xF;
            uint gv = (uv >> 0) & 0xF;

            //uint sf = RpfResourceFileEntry.GetFlagsFromSize(sysDataSize, sv);
            //uint gf = RpfResourceFileEntry.GetFlagsFromSize(gfxDataSize, gv); //TODO: might be broken...

            uint sf = RpfResourceFileEntry.GetFlagsFromBlocks((uint)systemPageCount, (uint)systemPageSize, sv);
            uint gf = RpfResourceFileEntry.GetFlagsFromBlocks((uint)graphicsPageCount, (uint)graphicsPageSize, gv);

            var tdatasize = sysDataSize + gfxDataSize;
            var tdata     = new byte[tdatasize];

            Buffer.BlockCopy(sysData, 0, tdata, 0, sysDataSize);
            Buffer.BlockCopy(gfxData, 0, tdata, sysDataSize, gfxDataSize);


            var cdata = compress ? Compress(tdata) : tdata;


            var dataSize = 16 + cdata.Length;// sysDataSize + gfxDataSize;
            var data     = new byte[dataSize];

            byte[] h1 = BitConverter.GetBytes((uint)0x37435352);
            byte[] h2 = BitConverter.GetBytes((int)version);
            byte[] h3 = BitConverter.GetBytes(sf);
            byte[] h4 = BitConverter.GetBytes(gf);
            Buffer.BlockCopy(h1, 0, data, 0, 4);
            Buffer.BlockCopy(h2, 0, data, 4, 4);
            Buffer.BlockCopy(h3, 0, data, 8, 4);
            Buffer.BlockCopy(h4, 0, data, 12, 4);
            Buffer.BlockCopy(cdata, 0, data, 16, cdata.Length);
            //Buffer.BlockCopy(sysData, 0, data, 16, sysDataSize);
            //Buffer.BlockCopy(gfxData, 0, data, 16 + sysDataSize, gfxDataSize);

            return(data);
        }