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; } }
public static void AssignPositions(IList <IResourceBlock> blocks, uint basePosition, out ResourceChunkFlags flags, uint usedPages) { flags = new ResourceChunkFlags(); if (blocks.Count <= 0) { return; } long largestBlockSize = 0; // find largest structure long startPageSize = BASE_SIZE; // 0x2000; // find starting page size long totalBlockSize = 0; foreach (var block in blocks) { // Get size of all blocks padded var blockLength = block.BlockLength; totalBlockSize += blockLength; totalBlockSize += Pad(totalBlockSize); // Get biggest block if (largestBlockSize < blockLength) { largestBlockSize = blockLength; } } // Get minimum page size to contain biggest block while (startPageSize < largestBlockSize) { startPageSize *= 2; } var pageSizeMult = 1; long currentPosition; var sys = (basePosition == 0x50000000); bool invalidLayout; do { invalidLayout = false; var blockset = new ResourceBuilderBlockSet(blocks, sys); var rootblock = blockset.RootBlock; currentPosition = 0L; var currentPageSize = startPageSize; var currentPageStart = 0L; var currentPageSpace = startPageSize; long currentRemainder = totalBlockSize; var bucketIndex = 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; } } flags = new ResourceChunkFlags(new uint[9], baseShift); var baseSizeMax = baseSize << 8; var baseSizeMaxTest = startPageSize; while (baseSizeMaxTest < baseSizeMax) { bucketIndex++; baseSizeMaxTest *= 2; } if (!flags.TryAddChunk(bucketIndex)) { break; } while (blockset.Count > 0) { var isroot = sys && (currentPosition == 0); var block = isroot ? rootblock : blockset.GetBestBlock(currentPageSpace); // If there is no block to fit in space left if (block == null) { //allocate a new page currentPageStart += currentPageSize; currentPosition = currentPageStart; // Get the biggest block block = blockset.GetBestBlock(long.MaxValue); var blockLength = block?.BlockLength ?? 0; // Get the smallest page which can contain the block while (blockLength <= (currentPageSize >> 1)) { if (currentPageSize <= minPageSize) { break; } if (bucketIndex >= 8) { break; } if ((currentPageSize <= targetPageSize) && (currentRemainder >= (currentPageSize - minPageSize))) { break; } currentPageSize = currentPageSize >> 1; bucketIndex++; } currentPageSpace = currentPageSize; // Try adding another chunk to this bucket if (!flags.TryAddChunk(bucketIndex)) { invalidLayout = true; break; } } //add this block to the current page. block.BlockPosition = basePosition + currentPosition; var opos = currentPosition; currentPosition += block.BlockLength; currentPosition += Pad(currentPosition); var usedspace = currentPosition - opos; currentPageSpace -= usedspace; currentRemainder -= usedspace; } startPageSize *= 2; pageSizeMult *= 2; }while ((invalidLayout) || (flags.Size < totalBlockSize) || (flags.Count + usedPages > 128)); }