Beispiel #1
0
            public static async Task <IvfcLevel> Load(IBinaryDataAccessor romfsData, IvfcLevelLocation location)
            {
                var header = new IvfcLevelHeader(await romfsData.ReadArrayAsync(location.DataOffset, 0x28));
                var level  = new IvfcLevel(romfsData.GetDataReference(location.DataOffset, location.DataSize), header);
                await level.Initialize();

                return(level);
            }
Beispiel #2
0
        public RomFs(IBinaryDataAccessor data, RomFsHeader header)
        {
            Data   = data ?? throw new ArgumentNullException(nameof(data));
            Header = header ?? throw new ArgumentNullException(nameof(header));

            LevelLocations = new IvfcLevelLocation[]
            {
                new IvfcLevelLocation
                {
                    HashBlockSize  = 1 << header.Level1BlockSize,
                        HashOffset = 0x60
                },
                new IvfcLevelLocation
                {
                    HashBlockSize = 1 << header.Level2BlockSize
                },
                new IvfcLevelLocation
                {
                    HashBlockSize = 1 << header.Level3BlockSize
                }
            };

            BodyOffset = Util.Align64(LevelLocations[0].HashOffset + header.MasterHashSize, LevelLocations[2].HashBlockSize);
            BodySize   = header.Level3HashDataSize;

            LevelLocations[2].DataOffset = BodyOffset;
            LevelLocations[2].DataSize   = Util.Align64(BodySize, LevelLocations[2].HashBlockSize);

            LevelLocations[1].HashOffset = Util.Align64(BodyOffset + BodySize, LevelLocations[2].HashBlockSize);
            LevelLocations[2].HashOffset = LevelLocations[1].HashOffset + header.Level2LogicalOffset - header.Level1LogicalOffset;

            LevelLocations[1].DataOffset = LevelLocations[2].HashOffset;
            LevelLocations[1].DataSize   = Util.Align64(header.Level2HashDataSize, LevelLocations[1].HashBlockSize);

            LevelLocations[0].DataOffset = LevelLocations[2].HashOffset;
            LevelLocations[0].DataSize   = Util.Align64(header.Level1HashDataSize, LevelLocations[0].HashBlockSize);

            // To-do: verify hashes
        }
        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);
        }