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); }