Пример #1
0
        private void AddFiles(List <RomfsFile> Entries)
        {
            string PrevDirPath = "";

            for (int i = 0; i < Entries.Count; i++)
            {
                var             fileName    = Path.GetFileName(Entries[i].FullName);
                Romfs_FileEntry Entry       = new Romfs_FileEntry();
                string          DirPath     = Path.GetDirectoryName(Entries[i].FullName);
                int             ParentIndex = GetRomfsDirEntry(DirPath);
                Entry.FullName        = Entries[i].FullName;
                Entry.Offset          = this.FileTableLen;
                Entry.ParentDirOffset = this.DirTable[ParentIndex].Offset;
                Entry.SiblingOffset   = ROMFS_UNUSED_ENTRY;
                if (DirPath == PrevDirPath)
                {
                    this.FileTable[i - 1].SiblingOffset = Entry.Offset;
                }
                if (this.DirTable[ParentIndex].FileOffset == ROMFS_UNUSED_ENTRY)
                {
                    this.DirTable[ParentIndex].FileOffset = Entry.Offset;
                }
                Entry.HashKeyPointer = ROMFS_UNUSED_ENTRY;
                Entry.NameSize       = fileName.Length * 2;
                Entry.Name           = fileName;
                Entry.DataOffset     = Entries[i].Offset;
                Entry.DataSize       = Entries[i].Size;
                this.FileTable.Add(Entry);
                this.FileTableLen += 0x20 + BitMath.Align(fileName.Length * 2, 4);
                PrevDirPath        = DirPath;
            }
        }
Пример #2
0
        public async Task Initalize()
        {
            var headerSize = await CiaData.ReadInt32Async(0);

            CiaHeader = new CiaHeader(await CiaData.ReadArrayAsync(0, headerSize));

            var certOffset    = BitMath.Align(headerSize, 64);
            var ticketOffset  = BitMath.Align(certOffset + CiaHeader.CertificateChainSize, 64);
            var tmdOffset     = BitMath.Align(ticketOffset + CiaHeader.TicketSize, 64);
            var contentOffset = BitMath.Align(tmdOffset + CiaHeader.TmdFileSize, 64);
            var metaOffset    = BitMath.Align(contentOffset + CiaHeader.ContentSize, 64);

            TmdMetadata = await TmdMetadata.Load(CiaData.GetReadOnlyDataReference(tmdOffset, CiaHeader.TmdFileSize));

            Partitions = new NcchPartition[TmdMetadata.ContentChunkRecords.Length];
            long partitionStart = contentOffset;

            for (var i = 0; i < TmdMetadata.ContentChunkRecords.Length; i++)
            {
                var chunkRecord     = TmdMetadata.ContentChunkRecords[i];
                var partitionLength = chunkRecord.ContentSize;
                int contentIndex    = chunkRecord.ContentIndex;

                Partitions[i] = await NcchPartition.Load(CiaData.GetReadOnlyDataReference(partitionStart, partitionLength));

                partitionStart += partitionLength;
            }

            IsDlcContainer = TmdMetadata.TitleId >> 32 == 0x0004008C;
        }
Пример #3
0
        private void CalcDirSize(string rootDirectory, IFileSystem fileSystem)
        {
            if (this.M_DirTableLen == 0)
            {
                this.M_DirTableLen = 0x18;
            }
            else
            {
                this.M_DirTableLen += 0x18 + BitMath.Align(Path.GetFileName(rootDirectory.TrimEnd('/')).Length * 2, 4);
            }

            var filePaths = fileSystem.GetFiles(rootDirectory, "*", true);

            foreach (var filePath in filePaths)
            {
                var filename = Path.GetFileName(filePath);
                this.M_FileTableLen += 0x20 + BitMath.Align(filename.Length * 2, 4);
            }

            var dirPaths = fileSystem.GetDirectories(rootDirectory, true);

            foreach (var dirPath in dirPaths)
            {
                CalcDirSize(dirPath, fileSystem);
            }

            this.FileNum += filePaths.Length;
            this.DirNum  += dirPaths.Length;
        }
Пример #4
0
        private void AddDir(string root, string directory, IFileSystem fileSystem, int parent, int sibling, bool DoSubs)
        {
            var dirName        = Path.GetFileName(directory.TrimEnd('/'));
            var SubDirectories = fileSystem.GetDirectories(directory, true);

            if (!DoSubs)
            {
                int            CurrentDir = this.DirTableLen;
                Romfs_DirEntry Entry      = new Romfs_DirEntry
                {
                    ParentOffset   = parent,
                    ChildOffset    = ROMFS_UNUSED_ENTRY,
                    HashKeyPointer = ROMFS_UNUSED_ENTRY,
                    FileOffset     = ROMFS_UNUSED_ENTRY,
                    SiblingOffset  = sibling,
                    FullName       = directory,
                    Name           = (directory == root) ? "" : dirName,
                    Offset         = CurrentDir
                };
                this.DirTable.Add(Entry);
                this.DirTableLen += (CurrentDir == 0) ? 0x18 : 0x18 + BitMath.Align(dirName.Length * 2, 4);
                int ParentIndex = GetRomfsDirEntry(directory);
                int poff        = this.DirTable[ParentIndex].Offset;
            }
            else
            {
                int CurIndex   = GetRomfsDirEntry(directory);
                int CurrentDir = this.DirTable[CurIndex].Offset;
                for (int i = 0; i < SubDirectories.Length; i++)
                {
                    AddDir(root, SubDirectories[i], fileSystem, CurrentDir, sibling, false);
                    if (i > 0)
                    {
                        string PrevFullName = SubDirectories[i - 1];
                        string ThisName     = SubDirectories[i];
                        int    PrevIndex    = GetRomfsDirEntry(PrevFullName);
                        int    ThisIndex    = GetRomfsDirEntry(ThisName);
                        this.DirTable[PrevIndex].SiblingOffset = this.DirTable[ThisIndex].Offset;
                    }
                }
                for (int i = 0; i < SubDirectories.Length; i++)
                {
                    AddDir(root, SubDirectories[i], fileSystem, CurrentDir, sibling, true);
                }
            }
            if (SubDirectories.Length > 0)
            {
                int curindex   = GetRomfsDirEntry(directory);
                int childindex = GetRomfsDirEntry(SubDirectories[0]);
                if (curindex > -1 && childindex > -1)
                {
                    this.DirTable[curindex].ChildOffset = this.DirTable[childindex].Offset;
                }
            }
        }
Пример #5
0
        private void CalcRomfsSize(string rootDirectory, IFileSystem fileSystem)
        {
            this.DirNum = 1;
            CalcDirSize(rootDirectory, fileSystem);

            this.M_DirHashTableEntry = GetHashTableEntryCount(this.DirNum);

            this.M_FileHashTableEntry = GetHashTableEntryCount(this.FileNum);

            int MetaDataSize = BitMath.Align(0x28 + this.M_DirHashTableEntry * 4 + this.M_DirTableLen + this.M_FileHashTableEntry * 4 + this.M_FileTableLen, PADDING_ALIGN);

            for (int i = 0; i < this.M_DirHashTableEntry; i++)
            {
                this.DirHashTable.Add(ROMFS_UNUSED_ENTRY);
            }
            for (int i = 0; i < this.M_FileHashTableEntry; i++)
            {
                this.FileHashTable.Add(ROMFS_UNUSED_ENTRY);
            }
            int Pos = this.InfoHeader.HeaderLength;

            for (int i = 0; i < 4; i++)
            {
                this.InfoHeader.Sections[i].Offset = Pos;
                int size = 0;
                switch (i)
                {
                case 0:
                    size = this.M_DirHashTableEntry * 4;
                    break;

                case 1:
                    size = this.M_DirTableLen;
                    break;

                case 2:
                    size = this.M_FileHashTableEntry * 4;
                    break;

                case 3:
                    size = this.M_FileTableLen;
                    break;
                }
                this.InfoHeader.Sections[i].Size = size;
                Pos += size;
            }
            this.InfoHeader.DataOffset = MetaDataSize;
        }
Пример #6
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);
        }
Пример #7
0
        /// <param name="data">The raw data. Note: This will be disposed when RomFs is disposed</param>
        public RomFs(IReadOnlyBinaryDataAccessor 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 = BitMath.Align(LevelLocations[0].HashOffset + header.MasterHashSize, LevelLocations[2].HashBlockSize);
            BodySize   = header.Level3HashDataSize;

            LevelLocations[2].DataOffset = BodyOffset;
            LevelLocations[2].DataSize   = BitMath.Align(BodySize, LevelLocations[2].HashBlockSize);

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

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

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

            // To-do: verify hashes
        }
Пример #8
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);
        }
Пример #9
0
        private byte[] WriteMetaDataToStream()
        {
            using (var stream = new MemoryStream())
            {
                //First, InfoHeader.
                stream.Write(BitConverter.GetBytes(this.InfoHeader.HeaderLength), 0, 4);
                foreach (Romfs_SectionHeader SH in this.InfoHeader.Sections)
                {
                    stream.Write(BitConverter.GetBytes(SH.Offset), 0, 4);
                    stream.Write(BitConverter.GetBytes(SH.Size), 0, 4);
                }
                stream.Write(BitConverter.GetBytes(this.InfoHeader.DataOffset), 0, 4);

                //DirHashTable
                foreach (uint u in this.DirHashTable)
                {
                    stream.Write(BitConverter.GetBytes(u), 0, 4);
                }

                //DirTable
                foreach (Romfs_DirEntry dir in this.DirTable)
                {
                    stream.Write(BitConverter.GetBytes(dir.ParentOffset), 0, 4);
                    stream.Write(BitConverter.GetBytes(dir.SiblingOffset), 0, 4);
                    stream.Write(BitConverter.GetBytes(dir.ChildOffset), 0, 4);
                    stream.Write(BitConverter.GetBytes(dir.FileOffset), 0, 4);
                    stream.Write(BitConverter.GetBytes(dir.HashKeyPointer), 0, 4);
                    uint nlen = (uint)dir.Name.Length * 2;
                    stream.Write(BitConverter.GetBytes(nlen), 0, 4);
                    byte[] NameArray = new byte[BitMath.Align(nlen, 4)];
                    Array.Copy(Encoding.Unicode.GetBytes(dir.Name), 0, NameArray, 0, nlen);
                    stream.Write(NameArray, 0, NameArray.Length);
                }

                //FileHashTable
                foreach (uint u in this.FileHashTable)
                {
                    stream.Write(BitConverter.GetBytes(u), 0, 4);
                }

                //FileTable
                foreach (Romfs_FileEntry file in this.FileTable)
                {
                    stream.Write(BitConverter.GetBytes(file.ParentDirOffset), 0, 4);
                    stream.Write(BitConverter.GetBytes(file.SiblingOffset), 0, 4);
                    stream.Write(BitConverter.GetBytes(file.DataOffset), 0, 8);
                    stream.Write(BitConverter.GetBytes(file.DataSize), 0, 8);
                    stream.Write(BitConverter.GetBytes(file.HashKeyPointer), 0, 4);
                    uint nlen = (uint)file.Name.Length * 2;
                    stream.Write(BitConverter.GetBytes(nlen), 0, 4);
                    byte[] NameArray = new byte[BitMath.Align(nlen, 4)];
                    Array.Copy(Encoding.Unicode.GetBytes(file.Name), 0, NameArray, 0, nlen);
                    stream.Write(NameArray, 0, NameArray.Length);
                }

                //Padding
                while (stream.Position % PADDING_ALIGN != 0)
                {
                    stream.Write(new byte[PADDING_ALIGN - (stream.Position % 0x10)], 0, (int)(PADDING_ALIGN - (stream.Position % 0x10)));
                }
                //All Done.

                return(stream.ToArray());
            }
        }