private static VolHeader BuildHeader(string directory) { VolHeader header = new VolHeader(); MemoryStream stringStream = new MemoryStream(); BinaryWriter nameString = new BinaryWriter(stringStream); VolHeaderEntry root = new VolHeaderEntry(); root.entryOffset = 0x14; root.parent = null; AppendVolHeaderFileName(nameString, ".", out root.nameOffset); uint runningFileDataOffset = 0; uint dirEntryIter = 0x14; uint fileInfoSize = 0; root.dataOffset = 0x14; root.entryOffset = 0x14; root.children = DirectoryToHeaderEntries(directory, nameString, ref dirEntryIter, ref runningFileDataOffset, ref fileInfoSize); nameString.Flush(); #if DEBUG Console.WriteLine( "Sizes: fileInfoOffset = {0:x}, fileInfoSize = {1:x}, runningFDO = {2:x}, nameString Length {3:x}", dirEntryIter, fileInfoSize, runningFileDataOffset, stringStream.Position ); #endif header.nameString = stringStream.ToArray(); header.fileInfoOffset = dirEntryIter; header.volEntries = root; header.nameOffset = header.fileInfoOffset + fileInfoSize; header.headerSize = header.nameOffset + (uint)header.nameString.Length; return(header); }
private static void WriteDirectory( BinaryWriter directoryWriter, BinaryWriter fileInfoWriter, uint fileInfoOffset, uint nameStringOffset, uint fileDataOffset, VolHeaderEntry dirEntry ) { directoryWriter.Write(0x01000000 | (dirEntry.nameOffset + nameStringOffset)); directoryWriter.Write(dirEntry.children.Count + 1); // +1 for the parent if (dirEntry.parent != null) { directoryWriter.Write(dirEntry.parent.entryOffset); } else { directoryWriter.Write(0); } List <MemoryStream> childDirDirectoryEntries = new List <MemoryStream>(); foreach (VolHeaderEntry child in dirEntry.children) { if (child.children != null) { directoryWriter.Write(child.dataOffset); MemoryStream childDirEntries = new MemoryStream(); BinaryWriter childDirWriter = new BinaryWriter(childDirEntries); WriteDirectory(childDirWriter, fileInfoWriter, fileInfoOffset, nameStringOffset, fileDataOffset, child); childDirDirectoryEntries.Add(childDirEntries); } else { directoryWriter.Write(child.fileInfoOffset + fileInfoOffset); uint highByte = 0; bool isCompressed = (child.decompFileSize != 0); if (isCompressed) { highByte = 0x02000000; } fileInfoWriter.Write(highByte | (child.nameOffset + nameStringOffset)); fileInfoWriter.Write((fileDataOffset + child.dataOffset) / 0x800); if (isCompressed) { fileInfoWriter.Write(child.decompFileSize); } fileInfoWriter.Write(child.fileSize); } } byte[] buffer = new byte[8192]; directoryWriter.Flush(); foreach (MemoryStream ms in childDirDirectoryEntries) { ms.Position = 0; StreamUtils.Copy(ms, directoryWriter.BaseStream, buffer); } }
private static List <VolHeaderEntry> DirectoryToHeaderEntries( string fsDirectory, BinaryWriter sb, ref uint nextDirStartOffset, ref uint fileDataRunningOffset, ref uint fileInfoSize ) { string[] entries = Directory.GetFileSystemEntries(fsDirectory); for (int i = 0; i < entries.Length; ++i) { if (entries[i].EndsWith(GT2Vol.VolFile.DecompDir, StringComparison.InvariantCultureIgnoreCase)) { string thisEntry = entries[i]; string last = entries[entries.Length - 1]; entries[i] = last; Array.Resize(ref entries, entries.Length - 1); --i; break; } } Array.Sort(entries); byte[] decompBuffer = new byte[65536]; // the 3 is for: // the name entry for this directory // the count that comes after the name offset // the offset to the parent directory // // running dir offset is for entries in this directory // nextDirStartOffset is where the next child directory will start uint runningDirOffset = nextDirStartOffset + (3 * sizeof(uint)); nextDirStartOffset += (uint)((entries.Length + 3) * sizeof(uint)); List <VolHeaderEntry> dirEntries = new List <VolHeaderEntry>(); char[] slashChars = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; foreach (string fileOrDir in entries) { int lastSlash = fileOrDir.LastIndexOfAny(slashChars); string lastPathPart = fileOrDir.Remove(0, lastSlash + 1); string fullFsPath = fileOrDir; VolHeaderEntry vhe = new VolHeaderEntry(); vhe.entryOffset = runningDirOffset; vhe.filePath = fullFsPath; AppendVolHeaderFileName(sb, lastPathPart, out vhe.nameOffset); if (Directory.Exists(fullFsPath)) { vhe.dataOffset = vhe.fileInfoOffset = nextDirStartOffset; vhe.children = DirectoryToHeaderEntries( fullFsPath, sb, ref nextDirStartOffset, ref fileDataRunningOffset, ref fileInfoSize ); foreach (VolHeaderEntry child in vhe.children) { child.parent = vhe; } } else { vhe.fileInfoOffset = fileInfoSize; fileInfoSize += (sizeof(uint) * 2); // name offset + fileSize vhe.dataOffset = fileDataRunningOffset; long fileSize = 0; uint decompSize = 0; using (FileStream fs = new FileStream(fullFsPath, FileMode.Open, FileAccess.Read)) { fileSize = fs.Length; // try to decompress if it looks like a gzip file if ((fs.ReadByte() == 0x1f) && (fs.ReadByte() == 0x8B)) { try { using (GZipInputStream gzIn = new GZipInputStream(fs)) using (MemoryStream ms = new MemoryStream()) { StreamUtils.Copy(gzIn, ms, decompBuffer); decompSize = (uint)ms.Position; fileInfoSize += sizeof(uint); // decomp size } } catch (Exception) { ; // probably isn't a gzip file afterall } } } vhe.fileSize = (uint)fileSize; vhe.decompFileSize = decompSize; // round up to next sector multiple fileSize = (fileSize + 0x7FF) & ~0x7FF; fileDataRunningOffset += (uint)fileSize; vhe.children = null; } runningDirOffset += sizeof(uint); dirEntries.Add(vhe); } return(dirEntries); }
public byte[] nameString; // already bitwise notted public VolHeader() { volEntries = new VolHeaderEntry(); }