示例#1
0
        public static void AssignPositions(IList <IResourceBlock> blocks, uint basePosition, out RpfResourcePageFlags pageFlags)
        {
            var sys = (basePosition == 0x50000000);

            long pad(long p)
            {
                return((ALIGN_SIZE - (p % ALIGN_SIZE)) % ALIGN_SIZE);
            }

            long largestBlockSize = 0;         // find largest structure
            long startPageSize    = BASE_SIZE; // 0x2000; // find starting page size
            long totalBlockSize   = 0;

            foreach (var block in blocks)
            {
                var blockLength = block.BlockLength;
                totalBlockSize += blockLength;
                totalBlockSize += pad(totalBlockSize);
                if (largestBlockSize < blockLength)
                {
                    largestBlockSize = blockLength;
                }
            }
            while (startPageSize < largestBlockSize)
            {
                startPageSize *= 2;
            }


            pageFlags = new RpfResourcePageFlags();
            var pageSizeMult = 1;

            while (true)
            {
                if (blocks.Count == 0)
                {
                    break;
                }

                var blockset         = new ResourceBuilderBlockSet(blocks, sys);
                var rootblock        = blockset.RootBlock;
                var currentPosition  = 0L;
                var currentPageSize  = startPageSize;
                var currentPageStart = 0L;
                var currentPageSpace = startPageSize;
                var currentRemainder = totalBlockSize;
                var pageCount        = 1;
                var pageCounts       = new uint[9];
                var pageCountIndex   = 0;
                var targetPageSize   = Math.Max(65536 * pageSizeMult, startPageSize >> (sys ? 5 : 2));
                var minPageSize      = Math.Max(512 * pageSizeMult, Math.Min(targetPageSize, startPageSize) >> 4);
                var baseShift        = 0u;
                var baseSize         = 512;
                while (baseSize < minPageSize)
                {
                    baseShift++;
                    baseSize *= 2;
                    if (baseShift >= 0xF)
                    {
                        break;
                    }
                }
                var baseSizeMax     = baseSize << 8;
                var baseSizeMaxTest = startPageSize;
                while (baseSizeMaxTest < baseSizeMax)
                {
                    pageCountIndex++;
                    baseSizeMaxTest *= 2;
                }
                pageCounts[pageCountIndex] = 1;

                while (true)
                {
                    var isroot      = sys && (currentPosition == 0);
                    var block       = isroot ? rootblock : blockset.TakeBestBlock(currentPageSpace);
                    var blockLength = block?.Length ?? 0;
                    if (block != null)
                    {
                        //add this block to the current page.
                        block.Block.FilePosition = basePosition + currentPosition;
                        var opos = currentPosition;
                        currentPosition += blockLength;
                        currentPosition += pad(currentPosition);
                        var usedspace = currentPosition - opos;
                        currentPageSpace -= usedspace;
                        currentRemainder -= usedspace;//blockLength;//
                    }
                    else if (blockset.Count > 0)
                    {
                        //allocate a new page
                        currentPageStart += currentPageSize;
                        currentPosition   = currentPageStart;
                        block             = blockset.FindBestBlock(long.MaxValue); //just find the biggest block
                        blockLength       = block?.Length ?? 0;
                        while (blockLength <= (currentPageSize >> 1))              //determine best new page size
                        {
                            if (currentPageSize <= minPageSize)
                            {
                                break;
                            }
                            if (pageCountIndex >= 8)
                            {
                                break;
                            }
                            if ((currentPageSize <= targetPageSize) && (currentRemainder >= (currentPageSize - minPageSize)))
                            {
                                break;
                            }

                            currentPageSize = currentPageSize >> 1;
                            pageCountIndex++;
                        }
                        currentPageSpace = currentPageSize;
                        pageCounts[pageCountIndex]++;
                        pageCount++;
                    }
                    else
                    {
                        break;
                    }
                }


                pageFlags = new RpfResourcePageFlags(pageCounts, baseShift);

                if ((pageCount == pageFlags.Count) && (pageFlags.Size >= currentPosition)) //make sure page counts fit in the flags value
                {
                    break;
                }

                startPageSize *= 2;
                pageSizeMult  *= 2;
            }
        }
示例#2
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));
        }