internal static void WriteMetaDataToStream(RomfsMetaData metaData, MemoryStream stream) { //First, InfoHeader. stream.Write(BitConverter.GetBytes(metaData.InfoHeader.HeaderLength), 0, 4); foreach (RomfsSectionHeader sh in metaData.InfoHeader.Sections) { stream.Write(BitConverter.GetBytes(sh.Offset), 0, 4); stream.Write(BitConverter.GetBytes(sh.Size), 0, 4); } stream.Write(BitConverter.GetBytes(metaData.InfoHeader.DataOffset), 0, 4); //DirHashTable foreach (uint u in metaData.DirHashTable) { stream.Write(BitConverter.GetBytes(u), 0, 4); } //DirTable foreach (RomfsDirEntry dir in metaData.DirTable.DirectoryTable) { 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[(int)RomFS.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 metaData.FileHashTable) { stream.Write(BitConverter.GetBytes(u), 0, 4); } //FileTable foreach (RomfsFileEntry file in metaData.FileTable.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[(int)RomFS.Align(nlen, 4)]; Array.Copy(Encoding.Unicode.GetBytes(file.Name), 0, nameArray, 0, nlen); stream.Write(nameArray, 0, nameArray.Length); } //Padding while (stream.Position % PaddingAlign != 0) { stream.Write(new byte[PaddingAlign - stream.Position % 0x10], 0, (int)(PaddingAlign - stream.Position % 0x10)); } //All Done. }
internal static void AddFiles(RomfsMetaData metaData, RomfsFile[] entries) { string prevDirPath = ""; for (int i = 0; i < entries.Length; i++) { FileInfo file = new FileInfo(entries[i].FullName); RomfsFileEntry entry = new RomfsFileEntry(); string dirPath = Path.GetDirectoryName(entries[i].FullName); int parentIndex = RomFS.GetRomfsDirEntry(metaData, dirPath); entry.FullName = entries[i].FullName; entry.Offset = metaData.FileTableLen; entry.ParentDirOffset = metaData.DirTable.DirectoryTable[parentIndex].Offset; entry.SiblingOffset = RomfsUnusedEntry; if (dirPath == prevDirPath) { metaData.FileTable.FileTable[i - 1].SiblingOffset = entry.Offset; } if (metaData.DirTable.DirectoryTable[parentIndex].FileOffset == RomfsUnusedEntry) { metaData.DirTable.DirectoryTable[parentIndex].FileOffset = entry.Offset; } entry.HashKeyPointer = RomfsUnusedEntry; 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)RomFS.Align((ulong)file.Name.Length * 2, 4); prevDirPath = dirPath; } }
internal static void CalcDirSize(RomfsMetaData metaData, DirectoryInfo dir) { if (metaData.MDirTableLen == 0) { metaData.MDirTableLen = 0x18; } else { metaData.MDirTableLen += 0x18 + (uint)RomFS.Align((ulong)dir.Name.Length * 2, 4); } FileInfo[] files = dir.GetFiles(); foreach (FileInfo t in files) { metaData.MFileTableLen += 0x20 + (uint)RomFS.Align((ulong)t.Name.Length * 2, 4); } DirectoryInfo[] subDirectories = dir.GetDirectories(); foreach (DirectoryInfo t in subDirectories) { RomFS.CalcDirSize(metaData, t); } metaData.FileNum += (uint)files.Length; metaData.DirNum += (uint)subDirectories.Length; }
internal static void CalcRomfsSize(RomfsMetaData metaData) { metaData.DirNum = 1; DirectoryInfo rootDi = new DirectoryInfo(RootDir); RomFS.CalcDirSize(metaData, rootDi); metaData.MDirHashTableEntry = RomFS.GetHashTableEntryCount(metaData.DirNum); metaData.MFileHashTableEntry = RomFS.GetHashTableEntryCount(metaData.FileNum); uint metaDataSize = (uint)RomFS.Align(0x28 + metaData.MDirHashTableEntry * 4 + metaData.MDirTableLen + metaData.MFileHashTableEntry * 4 + metaData.MFileTableLen, PaddingAlign); for (int i = 0; i < metaData.MDirHashTableEntry; i++) { metaData.DirHashTable.Add(RomfsUnusedEntry); } for (int i = 0; i < metaData.MFileHashTableEntry; i++) { metaData.FileHashTable.Add(RomfsUnusedEntry); } uint pos = metaData.InfoHeader.HeaderLength; for (int i = 0; i < 4; i++) { metaData.InfoHeader.Sections[i].Offset = pos; uint size = 0; switch (i) { case 0: size = metaData.MDirHashTableEntry * 4; break; case 1: size = metaData.MDirTableLen; break; case 2: size = metaData.MFileHashTableEntry * 4; break; case 3: size = metaData.MFileTableLen; break; } metaData.InfoHeader.Sections[i].Size = size; pos += size; } metaData.InfoHeader.DataOffset = metaDataSize; }
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 void AddDir(RomfsMetaData metaData, DirectoryInfo dir, uint parent, uint sibling, bool doSubs) { DirectoryInfo[] subDirectories = dir.GetDirectories(); if (!doSubs) { uint currentDir = metaData.DirTableLen; RomfsDirEntry entry = new RomfsDirEntry { ParentOffset = parent }; entry.ChildOffset = entry.HashKeyPointer = entry.FileOffset = RomfsUnusedEntry; entry.SiblingOffset = sibling; entry.FullName = dir.FullName; entry.Name = entry.FullName == RootDir ? "" : dir.Name; entry.Offset = currentDir; metaData.DirTable.DirectoryTable.Add(entry); metaData.DirTableLen += currentDir == 0 ? 0x18 : 0x18 + (uint)RomFS.Align((ulong)dir.Name.Length * 2, 4); // int ParentIndex = GetRomfsDirEntry(MetaData, Dir.FullName); // uint poff = MetaData.DirTable.DirectoryTable[ParentIndex].Offset; } else { int curIndex = RomFS.GetRomfsDirEntry(metaData, dir.FullName); uint currentDir = metaData.DirTable.DirectoryTable[curIndex].Offset; for (int i = 0; i < subDirectories.Length; i++) { RomFS.AddDir(metaData, subDirectories[i], currentDir, sibling, false); if (i <= 0) { continue; } string prevFullName = subDirectories[i - 1].FullName; string thisName = subDirectories[i].FullName; int prevIndex = RomFS.GetRomfsDirEntry(metaData, prevFullName); int thisIndex = RomFS.GetRomfsDirEntry(metaData, thisName); metaData.DirTable.DirectoryTable[prevIndex].SiblingOffset = metaData.DirTable.DirectoryTable[thisIndex].Offset; } foreach (DirectoryInfo t in subDirectories) { RomFS.AddDir(metaData, t, currentDir, sibling, true); } } if (subDirectories.Length <= 0) { return; } int curindex = RomFS.GetRomfsDirEntry(metaData, dir.FullName); int childindex = RomFS.GetRomfsDirEntry(metaData, subDirectories[0].FullName); if (curindex > -1 && childindex > -1) { metaData.DirTable.DirectoryTable[curindex].ChildOffset = metaData.DirTable.DirectoryTable[childindex].Offset; } }