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 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 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 AddFileHashKey(RomfsMetaData metaData, int index) { uint parent = metaData.FileTable.FileTable[index].ParentDirOffset; string name = metaData.FileTable.FileTable[index].Name; byte[] nArr = Encoding.Unicode.GetBytes(name); uint hash = RomFS.CalcPathHash(parent, nArr, 0); int ind2 = (int)(hash % metaData.MFileHashTableEntry); if (metaData.FileHashTable[ind2] == RomfsUnusedEntry) { metaData.FileHashTable[ind2] = metaData.FileTable.FileTable[index].Offset; } else { int i = RomFS.GetRomfsFileEntry(metaData, metaData.FileHashTable[ind2]); int tempindex = index; metaData.FileHashTable[ind2] = metaData.FileTable.FileTable[index].Offset; while (true) { if (metaData.FileTable.FileTable[tempindex].HashKeyPointer == RomfsUnusedEntry) { metaData.FileTable.FileTable[tempindex].HashKeyPointer = metaData.FileTable.FileTable[i].Offset; break; } i = tempindex; tempindex = RomFS.GetRomfsFileEntry(metaData, metaData.FileTable.FileTable[i].HashKeyPointer); } } }
internal static void BuildRomFSHeader(MemoryStream romfsStream, RomfsFile[] entries, string dir) { RootDir = dir; RomfsMetaData metaData = new RomfsMetaData(); RomFS.InitializeMetaData(metaData); RomFS.CalcRomfsSize(metaData); RomFS.PopulateRomfs(metaData, entries); RomFS.WriteMetaDataToStream(metaData, romfsStream); }
internal static void PopulateHashTables(RomfsMetaData metaData) { for (int i = 0; i < metaData.DirTable.DirectoryTable.Count; i++) { RomFS.AddDirHashKey(metaData, i); } for (int i = 0; i < metaData.FileTable.FileTable.Count; i++) { RomFS.AddFileHashKey(metaData, i); } }
internal static int GetRomfsFileEntry(RomfsMetaData metaData, uint offset) { for (int i = 0; i < metaData.FileTable.FileTable.Count; i++) { if (metaData.FileTable.FileTable[i].Offset == offset) { return(i); } } return(-1); }
internal static int GetRomfsDirEntry(RomfsMetaData metaData, uint offset) { for (int i = 0; i < metaData.DirTable.DirectoryTable.Count; i++) { if (metaData.DirTable.DirectoryTable[i].Offset == offset) { return(i); } } return(-1); }
//GetRomfs[...]Entry Functions are all O(n) internal static int GetRomfsDirEntry(RomfsMetaData metaData, string fullName) { for (int i = 0; i < metaData.DirTable.DirectoryTable.Count; i++) { if (metaData.DirTable.DirectoryTable[i].FullName == fullName) { return(i); } } return(-1); }
internal static void PopulateRomfs(RomfsMetaData metaData, RomfsFile[] entries) { //Recursively Add All Directories to DirectoryTable RomFS.AddDir(metaData, new DirectoryInfo(RootDir), 0, RomfsUnusedEntry); //Iteratively Add All Files to FileTable RomFS.AddFiles(metaData, entries); //Set Weird Offsets, Build HashKeyPointers, Build HashTables RomFS.PopulateHashTables(metaData); //Thats it. }
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 InitializeMetaData(RomfsMetaData metaData) { metaData.InfoHeader = new RomfsInfoHeader(); metaData.DirTable = new RomfsDirTable(); metaData.DirTableLen = 0; metaData.MDirTableLen = 0; metaData.FileTable = new RomfsFileTable(); metaData.FileTableLen = 0; metaData.DirTable.DirectoryTable = new List <RomfsDirEntry>(); metaData.FileTable.FileTable = new List <RomfsFileEntry>(); metaData.InfoHeader.HeaderLength = 0x28; metaData.InfoHeader.Sections = new RomfsSectionHeader[4]; metaData.DirHashTable = new List <uint>(); metaData.FileHashTable = new List <uint>(); }
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; } }
internal static void AddDir(RomfsMetaData metaData, DirectoryInfo dir, uint parent, uint sibling) { RomFS.AddDir(metaData, dir, parent, sibling, false); RomFS.AddDir(metaData, dir, parent, sibling, true); }