Exemplo n.º 1
0
        public static void BuildRomFS(string rootDirectory, IFileSystem fileSystem, Stream outputStream, ProcessingProgressedToken?progressToken = null)
        {
            var RomFiles = RomfsFile.LoadFromFileSystem(rootDirectory, fileSystem);
            var metadata = RomFsMetadataBuilder.BuildRomFSHeader(RomFiles, rootDirectory, fileSystem);

            MakeRomFSData(outputStream, fileSystem, RomFiles, metadata, progressToken);
        }
Exemplo n.º 2
0
        public static List <RomfsFile> LoadFromFileSystem(string rootDirectory, IFileSystem fileSystem)
        {
            var  list = new List <RomfsFile>();
            long Len  = 0;

            foreach (var filePath in fileSystem.GetFiles(rootDirectory, "*", false))
            {
                Len = BitMath.Align(Len, 0x10);

                var output = new RomfsFile
                {
                    FullName = filePath,
                    PathName = filePath.Replace(Path.GetFullPath(rootDirectory), "").Replace("\\", "/"),
                    Offset   = Len,
                    Size     = fileSystem.GetFileLength(filePath)
                };
                list.Add(output);

                Len += output.Size;
            }
            return(list);
        }
Exemplo n.º 3
0
        private static void MakeRomFSData(Stream outputStream, IFileSystem fileSystem, List <RomfsFile> RomFiles, byte[] metadata, ProcessingProgressedToken?progressToken = null)
        {
            // Computing IVFC Header Data...
            var ivfcLevels = new IvfcLevelLocation[3];

            for (int i = 0; i < ivfcLevels.Length; i++)
            {
                ivfcLevels[i] = new IvfcLevelLocation
                {
                    HashBlockSize = 0x1000
                };
            }
            ivfcLevels[2].DataSize = RomfsFile.GetDataBlockLength(RomFiles, metadata.Length);
            ivfcLevels[1].DataSize = (BitMath.Align(ivfcLevels[2].DataSize, ivfcLevels[2].HashBlockSize) / ivfcLevels[2].HashBlockSize) * 0x20; //0x20 per SHA256 hash
            ivfcLevels[0].DataSize = (BitMath.Align(ivfcLevels[1].DataSize, ivfcLevels[1].HashBlockSize) / ivfcLevels[1].HashBlockSize) * 0x20; //0x20 per SHA256 hash
            long MasterHashLen = (BitMath.Align(ivfcLevels[0].DataSize, ivfcLevels[0].HashBlockSize) / ivfcLevels[0].HashBlockSize) * 0x20;
            long lofs          = 0;

            for (int i = 0; i < ivfcLevels.Length; i++)
            {
                ivfcLevels[i].HashOffset = lofs;
                lofs += BitMath.Align(ivfcLevels[i].DataSize, ivfcLevels[i].HashBlockSize);
            }
            int IVFC_MAGIC      = 0x43465649; //IVFC
            int RESERVED        = 0x0;
            int HeaderLen       = 0x5C;
            int MEDIA_UNIT_SIZE = 0x200;

            byte[] SuperBlockHash = new byte[0x20];
            outputStream.Seek(0, SeekOrigin.Begin);
            outputStream.Write(BitConverter.GetBytes(IVFC_MAGIC), 0, 0x4);
            outputStream.Write(BitConverter.GetBytes(0x10000), 0, 0x4);
            outputStream.Write(BitConverter.GetBytes(MasterHashLen), 0, 0x4);
            for (int i = 0; i < ivfcLevels.Length; i++)
            {
                outputStream.Write(BitConverter.GetBytes(ivfcLevels[i].HashOffset), 0, 0x8);
                outputStream.Write(BitConverter.GetBytes(ivfcLevels[i].DataSize), 0, 0x8);
                outputStream.Write(BitConverter.GetBytes((int)(Math.Log(ivfcLevels[i].HashBlockSize, 2))), 0, 0x4);
                outputStream.Write(BitConverter.GetBytes(RESERVED), 0, 0x4);
            }
            outputStream.Write(BitConverter.GetBytes(HeaderLen), 0, 0x4);
            //IVFC Header is Written.
            outputStream.Seek(BitMath.Align(MasterHashLen + 0x60, ivfcLevels[0].HashBlockSize), SeekOrigin.Begin);
            outputStream.Write(metadata, 0, metadata.Length);
            long baseOfs = outputStream.Position;

            // Initialize progress token
            // The maximum will be the total file count and each ivfc block
            if (progressToken != null)
            {
                progressToken.ProcessedFileCount = 0;
                progressToken.TotalFileCount     = RomFiles.Count + ivfcLevels.Select(l => (int)(l.DataSize / l.HashBlockSize)).Sum();
            }

            // Writing Level 2 Data...
            for (int i = 0; i < RomFiles.Count; i++)
            {
                outputStream.Seek((long)(baseOfs + (long)RomFiles[i].Offset), SeekOrigin.Begin);
                using (var inStream = fileSystem.OpenFileReadOnly(RomFiles[i].FullName))
                {
                    while (inStream.Position < inStream.Length)
                    {
                        byte[] buffer = new byte[inStream.Length - inStream.Position > 0x100000 ? 0x100000 : inStream.Length - inStream.Position];
                        inStream.Read(buffer, 0, buffer.Length);
                        outputStream.Write(buffer, 0, buffer.Length);
                    }
                }

                if (progressToken != null)
                {
                    progressToken.ProcessedFileCount += 1;
                }
            }

            long          hashBaseOfs = BitMath.Align(outputStream.Position, ivfcLevels[2].HashBlockSize);
            long          hOfs        = BitMath.Align(MasterHashLen, ivfcLevels[0].HashBlockSize);
            long          cOfs        = hashBaseOfs + ivfcLevels[1].HashOffset;
            SHA256Managed sha         = new SHA256Managed();

            for (int i = ivfcLevels.Length - 1; i >= 0; i--)
            {
                // Computing Level {i} Hashes...
                byte[] buffer = new byte[(int)ivfcLevels[i].HashBlockSize];
                if (progressToken != null)
                {
                    progressToken.ProcessedFileCount = 0;
                    progressToken.TotalFileCount     = (int)(ivfcLevels[i].DataSize / ivfcLevels[i].HashBlockSize);
                }
                for (long ofs = 0; ofs < (long)ivfcLevels[i].DataSize; ofs += ivfcLevels[i].HashBlockSize)
                {
                    outputStream.Seek(hOfs, SeekOrigin.Begin);
                    outputStream.Read(buffer, 0, (int)ivfcLevels[i].HashBlockSize);
                    hOfs = outputStream.Position;
                    byte[] hash = sha.ComputeHash(buffer);
                    outputStream.Seek(cOfs, SeekOrigin.Begin);
                    outputStream.Write(hash, 0, hash.Length);
                    cOfs = outputStream.Position;

                    if (progressToken != null)
                    {
                        progressToken.ProcessedFileCount += 1;
                    }
                }
                if (i == 2)
                {
                    long len = outputStream.Position;
                    if (len % 0x1000 != 0)
                    {
                        len = BitMath.Align(len, 0x1000);
                        byte[] buf = new byte[len - outputStream.Position];
                        outputStream.Write(buf, 0, buf.Length);
                    }
                }
                if (i > 0)
                {
                    hOfs = hashBaseOfs + (long)ivfcLevels[i - 1].HashOffset;
                    if (i > 1)
                    {
                        cOfs = hashBaseOfs + (long)ivfcLevels[i - 2].HashOffset;
                    }
                    else
                    {
                        cOfs = BitMath.Align(HeaderLen, PADDING_ALIGN);
                    }
                }
            }
            outputStream.Seek(0, SeekOrigin.Begin);
            var SuperBlockLen = BitMath.Align(MasterHashLen + 0x60, MEDIA_UNIT_SIZE);

            byte[] MasterHashes = new byte[SuperBlockLen];
            outputStream.Read(MasterHashes, 0, (int)SuperBlockLen);
            SuperBlockHash = sha.ComputeHash(MasterHashes);
        }