internal static void BuildRomFS(string outfile, string infile, RichTextBox TB_Progress = null, ProgressBar PB_Show = null) { OutFile = outfile; ROOT_DIR = infile; if (File.Exists(TempFile)) File.Delete(TempFile); FileNameTable FNT = new FileNameTable(ROOT_DIR); RomfsFile[] RomFiles = new RomfsFile[FNT.NumFiles]; LayoutManager.Input[] In = new LayoutManager.Input[FNT.NumFiles]; updateTB(TB_Progress, "Creating Layout..."); for (int i = 0; i < FNT.NumFiles; i++) { In[i] = new LayoutManager.Input { FilePath = FNT.NameEntryTable[i].FullName, AlignmentSize = 0x10 }; } LayoutManager.Output[] Out = LayoutManager.Create(In); for (int i = 0; i < Out.Length; i++) { RomFiles[i] = new RomfsFile { Offset = Out[i].Offset, PathName = Out[i].FilePath.Replace(Path.GetFullPath(ROOT_DIR), "").Replace("\\", "/"), FullName = Out[i].FilePath, Size = Out[i].Size }; } using (MemoryStream memoryStream = new MemoryStream()) { updateTB(TB_Progress, "Creating RomFS MetaData..."); BuildRomFSHeader(memoryStream, RomFiles, ROOT_DIR); MakeRomFSData(RomFiles, memoryStream, TB_Progress, PB_Show); } }
public ArchiveFileInfo(RomFsFileSystem parent, RomfsFile file) { RomfsParent = parent; FullPath = file.FullPath; DataSize = file.DataLength; DataOffset = file.DataOffset; }
internal static void BuildRomFS(string infile, string outfile) { OutFile = outfile; RootDir = infile; if (File.Exists(TempFile)) { File.Delete(TempFile); } FileNameTable fnt = new FileNameTable(RootDir); RomfsFile[] romFiles = new RomfsFile[fnt.NumFiles]; LayoutManager.Input[] In = new LayoutManager.Input[fnt.NumFiles]; for (int i = 0; i < fnt.NumFiles; i++) { In[i] = new LayoutManager.Input { FilePath = fnt.NameEntryTable[i].FullName, AlignmentSize = 0x10 }; } LayoutManager.Output[] Out = LayoutManager.Create(In); for (int i = 0; i < Out.Length; i++) { romFiles[i] = new RomfsFile { Offset = Out[i].Offset, PathName = Out[i].FilePath.Replace(Path.GetFullPath(RootDir), "").Replace("\\", "/"), FullName = Out[i].FilePath, Size = Out[i].Size }; } using (MemoryStream memoryStream = new MemoryStream()) { RomFS.BuildRomFSHeader(memoryStream, romFiles, RootDir); RomFS.MakeRomFSData(romFiles, memoryStream); } }
public FileEntry(Romfs romfs, RomfsFile romfsFile, string root = "") { ParentROMFS = romfs; File = romfsFile; if (root != string.Empty) { FileName = $"{root}/Romfs/{File.FullPath}"; } else { FileName = $"Romfs/{File.FullPath}"; } }
// Thanks to Alex Barney for providing this code! public static void PopulateTreeView(TreeNodeCollection nodes, RomfsDir root) { RomfsFile fileNode = root.FirstFile; while (fileNode != null) { nodes.Add(fileNode.FullPath, fileNode.Name); fileNode = fileNode.NextSibling; } RomfsDir dirNode = root.FirstChild; while (dirNode != null) { TreeNode newNode = nodes.Add(dirNode.FullPath, dirNode.Name); PopulateTreeView(newNode.Nodes, dirNode); dirNode = dirNode.NextSibling; } }
public void FillTreeNodes(TreeNodeCollection nodes, RomfsDir romfsDir) { RomfsFile fileNode = romfsDir.FirstFile; while (fileNode != null) { var node = new FileNode(fileNode.FullPath, fileNode.Name); node.romfs = romfs; nodes.Add(node); fileNode = fileNode.NextSibling; } RomfsDir dirNode = romfsDir.FirstChild; while (dirNode != null) { TreeNode newNode = nodes.Add(dirNode.FullPath, dirNode.Name); FillTreeNodes(newNode.Nodes, dirNode); dirNode = dirNode.NextSibling; } }
internal static void MakeRomFSData(RomfsFile[] RomFiles, MemoryStream metadata, RichTextBox TB_Progress = null, ProgressBar PB_Show = null) { updateTB(TB_Progress, "Computing IVFC Header Data..."); IVFCInfo ivfc = new IVFCInfo { Levels = new IVFCLevel[3] }; for (int i = 0; i < ivfc.Levels.Length; i++) { ivfc.Levels[i] = new IVFCLevel { BlockSize = 0x1000 }; } ivfc.Levels[2].DataLength = RomfsFile.GetDataBlockLength(RomFiles, (ulong)metadata.Length); ivfc.Levels[1].DataLength = Align(ivfc.Levels[2].DataLength, ivfc.Levels[2].BlockSize) / ivfc.Levels[2].BlockSize * 0x20; //0x20 per SHA256 hash ivfc.Levels[0].DataLength = Align(ivfc.Levels[1].DataLength, ivfc.Levels[1].BlockSize) / ivfc.Levels[1].BlockSize * 0x20; //0x20 per SHA256 hash ulong MasterHashLen = Align(ivfc.Levels[0].DataLength, ivfc.Levels[0].BlockSize) / ivfc.Levels[0].BlockSize * 0x20; ulong lofs = 0; foreach (IVFCLevel t in ivfc.Levels) { t.HashOffset = lofs; lofs += Align(t.DataLength, t.BlockSize); } const uint IVFC_MAGIC = 0x43465649; //IVFC const uint RESERVED = 0x0; const uint HeaderLen = 0x5C; const uint MEDIA_UNIT_SIZE = 0x200; byte[] SuperBlockHash = new byte[0x20]; FileStream OutFileStream = new FileStream(TempFile, FileMode.Create, FileAccess.ReadWrite); try { OutFileStream.Seek(0, SeekOrigin.Begin); OutFileStream.Write(BitConverter.GetBytes(IVFC_MAGIC), 0, 0x4); OutFileStream.Write(BitConverter.GetBytes(0x10000), 0, 0x4); OutFileStream.Write(BitConverter.GetBytes(MasterHashLen), 0, 0x4); foreach (IVFCLevel t in ivfc.Levels) { OutFileStream.Write(BitConverter.GetBytes(t.HashOffset), 0, 0x8); OutFileStream.Write(BitConverter.GetBytes(t.DataLength), 0, 0x8); OutFileStream.Write(BitConverter.GetBytes((int)Math.Log(t.BlockSize, 2)), 0, 0x4); OutFileStream.Write(BitConverter.GetBytes(RESERVED), 0, 0x4); } OutFileStream.Write(BitConverter.GetBytes(HeaderLen), 0, 0x4); //IVFC Header is Written. OutFileStream.Seek((long)Align(MasterHashLen + 0x60, ivfc.Levels[0].BlockSize), SeekOrigin.Begin); byte[] metadataArray = metadata.ToArray(); OutFileStream.Write(metadataArray, 0, metadataArray.Length); long baseOfs = OutFileStream.Position; updateTB(TB_Progress, "Writing Level 2 Data..."); if (PB_Show.InvokeRequired) { PB_Show.Invoke((MethodInvoker) delegate { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = RomFiles.Length; }); } else { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = RomFiles.Length; } foreach (RomfsFile t in RomFiles) { OutFileStream.Seek(baseOfs + (long)t.Offset, SeekOrigin.Begin); using (FileStream inStream = new FileStream(t.FullName, FileMode.Open, FileAccess.Read)) { 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); OutFileStream.Write(buffer, 0, buffer.Length); } } if (PB_Show.InvokeRequired) { PB_Show.Invoke((MethodInvoker)PB_Show.PerformStep); } else { PB_Show.PerformStep(); } } long hashBaseOfs = (long)Align((ulong)OutFileStream.Position, ivfc.Levels[2].BlockSize); long hOfs = (long)Align(MasterHashLen, ivfc.Levels[0].BlockSize); long cOfs = hashBaseOfs + (long)ivfc.Levels[1].HashOffset; SHA256Managed sha = new SHA256Managed(); for (int i = ivfc.Levels.Length - 1; i >= 0; i--) { updateTB(TB_Progress, "Computing Level " + i + " Hashes..."); byte[] buffer = new byte[(int)ivfc.Levels[i].BlockSize]; var count = (int)(ivfc.Levels[i].DataLength / ivfc.Levels[i].BlockSize); if (PB_Show.InvokeRequired) { PB_Show.Invoke((MethodInvoker) delegate { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = count; }); } else { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = count; } for (long ofs = 0; ofs < (long)ivfc.Levels[i].DataLength; ofs += ivfc.Levels[i].BlockSize) { OutFileStream.Seek(hOfs, SeekOrigin.Begin); OutFileStream.Read(buffer, 0, (int)ivfc.Levels[i].BlockSize); hOfs = OutFileStream.Position; byte[] hash = sha.ComputeHash(buffer); OutFileStream.Seek(cOfs, SeekOrigin.Begin); OutFileStream.Write(hash, 0, hash.Length); cOfs = OutFileStream.Position; if (PB_Show.InvokeRequired) { PB_Show.Invoke((MethodInvoker)PB_Show.PerformStep); } else { PB_Show.PerformStep(); } } if (i <= 0) { continue; } if (i == 2) { long len = OutFileStream.Position; if (len % 0x1000 != 0) { len = (long)Align((ulong)len, 0x1000); byte[] buf = new byte[len - OutFileStream.Position]; OutFileStream.Write(buf, 0, buf.Length); } } hOfs = hashBaseOfs + (long)ivfc.Levels[i - 1].HashOffset; if (i > 1) { cOfs = hashBaseOfs + (long)ivfc.Levels[i - 2].HashOffset; } else { cOfs = (long)Align(HeaderLen, PADDING_ALIGN); } } OutFileStream.Seek(0, SeekOrigin.Begin); uint SuperBlockLen = (uint)Align(MasterHashLen + 0x60, MEDIA_UNIT_SIZE); byte[] MasterHashes = new byte[SuperBlockLen]; OutFileStream.Read(MasterHashes, 0, (int)SuperBlockLen); SuperBlockHash = sha.ComputeHash(MasterHashes); } finally { OutFileStream.Dispose(); } if (OutFile == TempFile) { return; } if (File.Exists(OutFile)) { File.Delete(OutFile); } File.Move(TempFile, OutFile); }
public FileEntry(Romfs romfs, RomfsFile romfsFile) { ParentROMFS = romfs; File = romfsFile; FileName = $"Romfs/{File.FullPath}"; }
public static ulong GetDataBlockLength(RomfsFile[] files, ulong PreData) { return (files.Length == 0) ? PreData : PreData + files[files.Length - 1].Offset + files[files.Length - 1].Size; }
internal static void PopulateRomfs(Romfs_MetaData MetaData, RomfsFile[] Entries) { //Recursively Add All Directories to DirectoryTable AddDir(MetaData, new DirectoryInfo(ROOT_DIR), 0, ROMFS_UNUSED_ENTRY); //Iteratively Add All Files to FileTable AddFiles(MetaData, Entries); //Set Weird Offsets, Build HashKeyPointers, Build HashTables PopulateHashTables(MetaData); //Thats it. }
internal static Stream BuildRomFS(string outfile, string infile, string _patchDir) { OutFile = outfile; ROOT_DIR = infile; if (outfile != null) { if (File.Exists(TempFile)) { File.Delete(TempFile); } } FileNameTable FNT = new FileNameTable(ROOT_DIR); RomfsFile[] RomFiles = new RomfsFile[FNT.NumFiles]; LayoutManager.Input[] In = new LayoutManager.Input[FNT.NumFiles]; updateTB("Creating Layout..."); for (int i = 0; i < FNT.NumFiles; i++) { In[i] = new LayoutManager.Input { FilePath = FNT.NameEntryTable[i].FullName, AlignmentSize = 0x10 }; } String[] _relativePaths = new String[FNT.NumFiles]; for (int i = 0; i < _relativePaths.Length; ++i) { _relativePaths[i] = makePathRelative(In[i].FilePath, ROOT_DIR); } if (_patchDir != null) { string[] _altFiles = Directory.GetFiles(_patchDir, "*", SearchOption.AllDirectories); for (int i = 0; i < _altFiles.Length; ++i) { string _stippedStart = makePathRelative(_altFiles[i], _patchDir); int j; for (j = 0; j < In.Length; ++j) { if (_relativePaths[j] == _stippedStart) { In[j].FilePath = _altFiles[i]; break; } } } } LayoutManager.Output[] Out = LayoutManager.Create(In); for (int i = 0; i < Out.Length; i++) { RomFiles[i] = new RomfsFile { Offset = Out[i].Offset, PathName = _relativePaths[i], FullName = FNT.NameEntryTable[i].FullName, realFilePath = In[i].FilePath, Size = Out[i].Size }; } Stream _possibleRetStream; using (MemoryStream memoryStream = new MemoryStream()) { updateTB("Creating RomFS MetaData..."); BuildRomFSHeader(memoryStream, RomFiles, ROOT_DIR); _possibleRetStream = MakeRomFSData(RomFiles, memoryStream, outfile != null ? outfile : null); } if (outfile != null) { return(null); } else { return(_possibleRetStream); } }
internal static void BuildRomFSHeader(MemoryStream romfs_stream, RomfsFile[] Entries, string DIR) { ROOT_DIR = DIR; Romfs_MetaData MetaData = new Romfs_MetaData(); InitializeMetaData(MetaData); CalcRomfsSize(MetaData); PopulateRomfs(MetaData, Entries); WriteMetaDataToStream(MetaData, romfs_stream); }
internal static void AddFiles(Romfs_MetaData MetaData, RomfsFile[] Entries) { string PrevDirPath = ""; for (int i = 0; i < Entries.Length; i++) { FileInfo file = new FileInfo(Entries[i].FullName); Romfs_FileEntry Entry = new Romfs_FileEntry(); string DirPath = Path.GetDirectoryName(Entries[i].FullName); int ParentIndex = GetRomfsDirEntry(MetaData, DirPath); Entry.FullName = Entries[i].FullName; Entry.Offset = MetaData.FileTableLen; Entry.ParentDirOffset = MetaData.DirTable.DirectoryTable[ParentIndex].Offset; Entry.SiblingOffset = ROMFS_UNUSED_ENTRY; if (DirPath == PrevDirPath) { MetaData.FileTable.FileTable[i - 1].SiblingOffset = Entry.Offset; } if (MetaData.DirTable.DirectoryTable[ParentIndex].FileOffset == ROMFS_UNUSED_ENTRY) { MetaData.DirTable.DirectoryTable[ParentIndex].FileOffset = Entry.Offset; } Entry.HashKeyPointer = ROMFS_UNUSED_ENTRY; Entry.NameSize = (uint)file.Name.Length * 2; Entry.Name = file.Name; Entry.DataOffset = Entries[i].Offset; Entry.DataSize = Entries[i].Size; MetaData.FileTable.FileTable.Add(Entry); MetaData.FileTableLen += 0x20 + (uint)Align((ulong)file.Name.Length * 2, 4); PrevDirPath = DirPath; } }
internal static void MakeRomFSData(RomfsFile[] RomFiles, MemoryStream metadata, RichTextBox TB_Progress = null, ProgressBar PB_Show = null) { updateTB(TB_Progress, "Computing IVFC Header Data..."); IVFCInfo ivfc = new IVFCInfo { Levels = new IVFCLevel[3] }; for (int i = 0; i < ivfc.Levels.Length; i++) { ivfc.Levels[i] = new IVFCLevel { BlockSize = 0x1000 }; } ivfc.Levels[2].DataLength = RomfsFile.GetDataBlockLength(RomFiles, (ulong)metadata.Length); ivfc.Levels[1].DataLength = (Align(ivfc.Levels[2].DataLength, ivfc.Levels[2].BlockSize) / ivfc.Levels[2].BlockSize) * 0x20; //0x20 per SHA256 hash ivfc.Levels[0].DataLength = (Align(ivfc.Levels[1].DataLength, ivfc.Levels[1].BlockSize) / ivfc.Levels[1].BlockSize) * 0x20; //0x20 per SHA256 hash ulong MasterHashLen = (Align(ivfc.Levels[0].DataLength, ivfc.Levels[0].BlockSize) / ivfc.Levels[0].BlockSize) * 0x20; ulong lofs = 0; foreach (IVFCLevel t in ivfc.Levels) { t.HashOffset = lofs; lofs += Align(t.DataLength, t.BlockSize); } const uint IVFC_MAGIC = 0x43465649; //IVFC const uint RESERVED = 0x0; const uint HeaderLen = 0x5C; FileStream OutFileStream = new FileStream(TempFile, FileMode.Create, FileAccess.ReadWrite); try { OutFileStream.Seek(0, SeekOrigin.Begin); OutFileStream.Write(BitConverter.GetBytes(IVFC_MAGIC), 0, 0x4); OutFileStream.Write(BitConverter.GetBytes(0x10000), 0, 0x4); OutFileStream.Write(BitConverter.GetBytes(MasterHashLen), 0, 0x4); foreach (IVFCLevel t in ivfc.Levels) { OutFileStream.Write(BitConverter.GetBytes(t.HashOffset), 0, 0x8); OutFileStream.Write(BitConverter.GetBytes(t.DataLength), 0, 0x8); OutFileStream.Write(BitConverter.GetBytes((int)(Math.Log(t.BlockSize, 2))), 0, 0x4); OutFileStream.Write(BitConverter.GetBytes(RESERVED), 0, 0x4); } OutFileStream.Write(BitConverter.GetBytes(HeaderLen), 0, 0x4); //IVFC Header is Written. OutFileStream.Seek((long)Align(MasterHashLen + 0x60, ivfc.Levels[0].BlockSize), SeekOrigin.Begin); byte[] metadataArray = metadata.ToArray(); OutFileStream.Write(metadataArray, 0, metadataArray.Length); long baseOfs = OutFileStream.Position; updateTB(TB_Progress, "Writing Level 2 Data..."); if (PB_Show.InvokeRequired) PB_Show.Invoke((MethodInvoker)delegate { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = RomFiles.Length; }); else { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = RomFiles.Length; } foreach (RomfsFile t in RomFiles) { OutFileStream.Seek(baseOfs + (long)t.Offset, SeekOrigin.Begin); using (FileStream inStream = new FileStream(t.FullName, FileMode.Open, FileAccess.Read)) { 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); OutFileStream.Write(buffer, 0, buffer.Length); } } if (PB_Show.InvokeRequired) PB_Show.Invoke((MethodInvoker)delegate { PB_Show.PerformStep(); }); else { PB_Show.PerformStep(); } } long hashBaseOfs = (long)Align((ulong)OutFileStream.Position, ivfc.Levels[2].BlockSize); long hOfs = (long)Align(MasterHashLen, ivfc.Levels[0].BlockSize); long cOfs = hashBaseOfs + (long)ivfc.Levels[1].HashOffset; SHA256Managed sha = new SHA256Managed(); for (int i = ivfc.Levels.Length - 1; i >= 0; i--) { updateTB(TB_Progress, "Computing Level " + i + " Hashes..."); byte[] buffer = new byte[(int)ivfc.Levels[i].BlockSize]; if (PB_Show.InvokeRequired) PB_Show.Invoke((MethodInvoker)delegate { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = (int)(ivfc.Levels[i].DataLength / ivfc.Levels[i].BlockSize); }); else { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = (int)(ivfc.Levels[i].DataLength / ivfc.Levels[i].BlockSize); } for (long ofs = 0; ofs < (long)ivfc.Levels[i].DataLength; ofs += ivfc.Levels[i].BlockSize) { OutFileStream.Seek(hOfs, SeekOrigin.Begin); OutFileStream.Read(buffer, 0, (int)ivfc.Levels[i].BlockSize); hOfs = OutFileStream.Position; byte[] hash = sha.ComputeHash(buffer); OutFileStream.Seek(cOfs, SeekOrigin.Begin); OutFileStream.Write(hash, 0, hash.Length); cOfs = OutFileStream.Position; if (PB_Show.InvokeRequired) PB_Show.Invoke((MethodInvoker)delegate { PB_Show.PerformStep(); }); else { PB_Show.PerformStep(); } } if (i == 2) { long len = OutFileStream.Position; if (len % 0x1000 != 0) { len = (long)Align((ulong)len, 0x1000); byte[] buf = new byte[len - OutFileStream.Position]; OutFileStream.Write(buf, 0, buf.Length); } } if (i <= 0) continue; hOfs = hashBaseOfs + (long)ivfc.Levels[i - 1].HashOffset; if (i > 1) cOfs = hashBaseOfs + (long)ivfc.Levels[i - 2].HashOffset; else cOfs = (long)Align(HeaderLen, PADDING_ALIGN); } } finally { if (OutFileStream != null) OutFileStream.Dispose(); } if (OutFile != TempFile) { if (File.Exists(OutFile)) File.Delete(OutFile); File.Move(TempFile, OutFile); } }
internal static void MakeRomFSData(RomfsFile[] romFiles, MemoryStream metadata) { IvfcInfo ivfc = new IvfcInfo { Levels = new IvfcLevel[3] }; for (int i = 0; i < ivfc.Levels.Length; i++) { ivfc.Levels[i] = new IvfcLevel { BlockSize = 0x1000 }; } ivfc.Levels[2].DataLength = RomfsFile.GetDataBlockLength(romFiles, (ulong)metadata.Length); ivfc.Levels[1].DataLength = RomFS.Align(ivfc.Levels[2].DataLength, ivfc.Levels[2].BlockSize) / ivfc.Levels[2].BlockSize * 0x20; //0x20 per SHA256 hash ivfc.Levels[0].DataLength = RomFS.Align(ivfc.Levels[1].DataLength, ivfc.Levels[1].BlockSize) / ivfc.Levels[1].BlockSize * 0x20; //0x20 per SHA256 hash ulong masterHashLen = RomFS.Align(ivfc.Levels[0].DataLength, ivfc.Levels[0].BlockSize) / ivfc.Levels[0].BlockSize * 0x20; ulong lofs = 0; foreach (IvfcLevel t in ivfc.Levels) { t.HashOffset = lofs; lofs += RomFS.Align(t.DataLength, t.BlockSize); } const uint ivfcMagic = 0x43465649; //IVFC const uint reserved = 0x0; const uint headerLen = 0x5C; const uint mediaUnitSize = 0x200; FileStream outFileStream = new FileStream(TempFile, FileMode.Create, FileAccess.ReadWrite); try { outFileStream.Seek(0, SeekOrigin.Begin); outFileStream.Write(BitConverter.GetBytes(ivfcMagic), 0, 0x4); outFileStream.Write(BitConverter.GetBytes(0x10000), 0, 0x4); outFileStream.Write(BitConverter.GetBytes(masterHashLen), 0, 0x4); foreach (IvfcLevel t in ivfc.Levels) { outFileStream.Write(BitConverter.GetBytes(t.HashOffset), 0, 0x8); outFileStream.Write(BitConverter.GetBytes(t.DataLength), 0, 0x8); outFileStream.Write(BitConverter.GetBytes((int)Math.Log(t.BlockSize, 2)), 0, 0x4); outFileStream.Write(BitConverter.GetBytes(reserved), 0, 0x4); } outFileStream.Write(BitConverter.GetBytes(headerLen), 0, 0x4); //IVFC Header is Written. outFileStream.Seek((long)RomFS.Align(masterHashLen + 0x60, ivfc.Levels[0].BlockSize), SeekOrigin.Begin); byte[] metadataArray = metadata.ToArray(); outFileStream.Write(metadataArray, 0, metadataArray.Length); long baseOfs = outFileStream.Position; foreach (RomfsFile t in romFiles) { outFileStream.Seek(baseOfs + (long)t.Offset, SeekOrigin.Begin); using (FileStream inStream = new FileStream(t.FullName, FileMode.Open, FileAccess.Read)) { 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); outFileStream.Write(buffer, 0, buffer.Length); } } } long hashBaseOfs = (long)RomFS.Align((ulong)outFileStream.Position, ivfc.Levels[2].BlockSize); long hOfs = (long)RomFS.Align(masterHashLen, ivfc.Levels[0].BlockSize); long cOfs = hashBaseOfs + (long)ivfc.Levels[1].HashOffset; SHA256Managed sha = new SHA256Managed(); for (int i = ivfc.Levels.Length - 1; i >= 0; i--) { byte[] buffer = new byte[(int)ivfc.Levels[i].BlockSize]; for (long ofs = 0; ofs < (long)ivfc.Levels[i].DataLength; ofs += ivfc.Levels[i].BlockSize) { outFileStream.Seek(hOfs, SeekOrigin.Begin); outFileStream.Read(buffer, 0, (int)ivfc.Levels[i].BlockSize); hOfs = outFileStream.Position; byte[] hash = sha.ComputeHash(buffer); outFileStream.Seek(cOfs, SeekOrigin.Begin); outFileStream.Write(hash, 0, hash.Length); cOfs = outFileStream.Position; } if (i <= 0) { continue; } if (i == 2) { long len = outFileStream.Position; if (len % 0x1000 != 0) { len = (long)RomFS.Align((ulong)len, 0x1000); byte[] buf = new byte[len - outFileStream.Position]; outFileStream.Write(buf, 0, buf.Length); } } hOfs = hashBaseOfs + (long)ivfc.Levels[i - 1].HashOffset; if (i > 1) { cOfs = hashBaseOfs + (long)ivfc.Levels[i - 2].HashOffset; } else { cOfs = (long)RomFS.Align(headerLen, PaddingAlign); } } outFileStream.Seek(0, SeekOrigin.Begin); uint superBlockLen = (uint)RomFS.Align(masterHashLen + 0x60, mediaUnitSize); byte[] masterHashes = new byte[superBlockLen]; outFileStream.Read(masterHashes, 0, (int)superBlockLen); sha.ComputeHash(masterHashes); } finally { outFileStream.Dispose(); } if (OutFile == TempFile) { return; } if (File.Exists(OutFile)) { File.Delete(OutFile); } File.Move(TempFile, OutFile); }
internal static Stream MakeRomFSData(RomfsFile[] RomFiles, MemoryStream metadata, string _writeDest) { updateTB("Computing IVFC Header Data..."); IVFCInfo ivfc = new IVFCInfo { Levels = new IVFCLevel[3] }; for (int i = 0; i < ivfc.Levels.Length; i++) { ivfc.Levels[i] = new IVFCLevel { BlockSize = 0x1000 }; } ivfc.Levels[2].DataLength = RomfsFile.GetDataBlockLength(RomFiles, (ulong)metadata.Length); ivfc.Levels[1].DataLength = (Align(ivfc.Levels[2].DataLength, ivfc.Levels[2].BlockSize) / ivfc.Levels[2].BlockSize) * 0x20; //0x20 per SHA256 hash ivfc.Levels[0].DataLength = (Align(ivfc.Levels[1].DataLength, ivfc.Levels[1].BlockSize) / ivfc.Levels[1].BlockSize) * 0x20; //0x20 per SHA256 hash ulong MasterHashLen = (Align(ivfc.Levels[0].DataLength, ivfc.Levels[0].BlockSize) / ivfc.Levels[0].BlockSize) * 0x20; ulong lofs = 0; foreach (IVFCLevel t in ivfc.Levels) { t.HashOffset = lofs; lofs += Align(t.DataLength, t.BlockSize); } const uint IVFC_MAGIC = 0x43465649; //IVFC const uint RESERVED = 0x0; const uint HeaderLen = 0x5C; Stream OutFileStream; if (_writeDest != null) { OutFileStream = new FileStream(TempFile, FileMode.Create, FileAccess.ReadWrite); } else { OutFileStream = new MemoryStream(); } try { OutFileStream.Seek(0, SeekOrigin.Begin); OutFileStream.Write(BitConverter.GetBytes(IVFC_MAGIC), 0, 0x4); OutFileStream.Write(BitConverter.GetBytes(0x10000), 0, 0x4); OutFileStream.Write(BitConverter.GetBytes(MasterHashLen), 0, 0x4); foreach (IVFCLevel t in ivfc.Levels) { OutFileStream.Write(BitConverter.GetBytes(t.HashOffset), 0, 0x8); OutFileStream.Write(BitConverter.GetBytes(t.DataLength), 0, 0x8); OutFileStream.Write(BitConverter.GetBytes((int)(Math.Log(t.BlockSize, 2))), 0, 0x4); OutFileStream.Write(BitConverter.GetBytes(RESERVED), 0, 0x4); } OutFileStream.Write(BitConverter.GetBytes(HeaderLen), 0, 0x4); //IVFC Header is Written. OutFileStream.Seek((long)Align(MasterHashLen + 0x60, ivfc.Levels[0].BlockSize), SeekOrigin.Begin); byte[] metadataArray = metadata.ToArray(); OutFileStream.Write(metadataArray, 0, metadataArray.Length); long baseOfs = OutFileStream.Position; updateTB("Writing Level 2 Data..."); foreach (RomfsFile t in RomFiles) { OutFileStream.Seek(baseOfs + (long)t.Offset, SeekOrigin.Begin); using (FileStream inStream = new FileStream(t.realFilePath, FileMode.Open, FileAccess.Read)) { 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); OutFileStream.Write(buffer, 0, buffer.Length); } } } long hashBaseOfs = (long)Align((ulong)OutFileStream.Position, ivfc.Levels[2].BlockSize); long hOfs = (long)Align(MasterHashLen, ivfc.Levels[0].BlockSize); long cOfs = hashBaseOfs + (long)ivfc.Levels[1].HashOffset; SHA256Managed sha = new SHA256Managed(); for (int i = ivfc.Levels.Length - 1; i >= 0; i--) { updateTB("Computing Level " + i + " Hashes..."); byte[] buffer = new byte[(int)ivfc.Levels[i].BlockSize]; for (long ofs = 0; ofs < (long)ivfc.Levels[i].DataLength; ofs += ivfc.Levels[i].BlockSize) { OutFileStream.Seek(hOfs, SeekOrigin.Begin); OutFileStream.Read(buffer, 0, (int)ivfc.Levels[i].BlockSize); hOfs = OutFileStream.Position; byte[] hash = sha.ComputeHash(buffer); OutFileStream.Seek(cOfs, SeekOrigin.Begin); OutFileStream.Write(hash, 0, hash.Length); cOfs = OutFileStream.Position; } if (i == 2) { long len = OutFileStream.Position; if (len % 0x1000 != 0) { len = (long)Align((ulong)len, 0x1000); byte[] buf = new byte[len - OutFileStream.Position]; OutFileStream.Write(buf, 0, buf.Length); } } if (i <= 0) { continue; } hOfs = hashBaseOfs + (long)ivfc.Levels[i - 1].HashOffset; if (i > 1) { cOfs = hashBaseOfs + (long)ivfc.Levels[i - 2].HashOffset; } else { cOfs = (long)Align(HeaderLen, PADDING_ALIGN); } } } finally { if (OutFileStream != null && _writeDest != null) { OutFileStream.Dispose(); } } if (_writeDest != null) { OutFileStream.Dispose(); if (_writeDest != TempFile) { if (File.Exists(OutFile)) { File.Delete(OutFile); } File.Move(TempFile, OutFile); } return(null); } else { return(OutFileStream); } }