public static void Explode(string[] args, VolFile.ExplodeProgressCallback callback) { if (!File.Exists(args[1])) { Console.Error.WriteLine("VOL file '{0}' doesn't exist!", args[1]); return; } GT3Vol volFile = new GT3Vol(args[1]); volFile.Extract(args[2], args.Length >= 4, callback); }
public void WriteNewVol(string newVol, HeaderInfo hi, List <FSEntry> entries, VolFile.ExplodeProgressCallback callback) { // the Vol file is massive, about 500 MB // I don't want to have to write out the file data section to an actual file and have to read it back in // to copy it to the final file. So ~500MB of memory it is using (MemoryStream fileData = new MemoryStream(500000000)) { int[] offsets = hi.offsets; int nextOffset = hi.fileDataStartPosition; byte[] padBytes = new byte[0x7ff]; BinaryWriter bw = new BinaryWriter(fileData); int fileCount = 0; foreach (FSEntry entry in entries) { int size = 0; if ((entry.tocEntry.flags & TOCFlags_Directory) == 0) { // if we recompressed the file, just write its bytes out if (entry.compressedFile != null) { size = entry.compressedFile.Length; bw.Write(entry.compressedFile); } else { // otherwise read it in and write it to the memory using (FileStream fs = new FileStream(entry.diskFile, FileMode.Open, FileAccess.Read)) { size = (int)fs.Length; byte[] d = new byte[0x8000]; int read = 0; while ((read = fs.Read(d, 0, d.Length)) > 0) { bw.Write(d, 0, read); } } } // write the pad bytes int remainder = 0x800 - (size % 0x800); if (remainder == 0x800) { remainder = 0; } bw.Write(padBytes, 0, remainder); callback(String.Format("Wrote {0} at 0x{1:x}, padded with 0x{2:x} bytes", entry.name, nextOffset, remainder)); offsets[2 + fileCount] = nextOffset | remainder; nextOffset += size + remainder; Debug.Assert((nextOffset & 0x7FF) == 0); ++fileCount; } } bw.Flush(); fileData.Position = 0; offsets[offsets.Length - 1] = nextOffset; // last one is the file size using (FileStream newVolFile = new FileStream(newVol, FileMode.Create, FileAccess.Write)) { byte[] offBytes = new byte[offsets.Length * sizeof(int)]; Buffer.BlockCopy(offsets, 0, offBytes, 0, offBytes.Length); // header newVolFile.Write(hi.header, 0, hi.header.Length); // offsets newVolFile.Write(offBytes, 0, offBytes.Length); // padding for offsets newVolFile.Write(padBytes, 0, offsets[0] & 0x7ff); // toc hi.toc.Position = 0; StreamUtils.Copy(hi.toc, newVolFile, offBytes); // toc padding newVolFile.Write(padBytes, 0, offsets[1] & 0x7ff); // file data StreamUtils.Copy(fileData, newVolFile, offBytes); } } }
public void Extract(string path, bool decomp, VolFile.ExplodeProgressCallback callback) { ExtractDirectory(rootVolEntry.children, path, decomp, callback); }
private void ExtractDirectory(List <VolEntryInfo> dirEntries, string dirPath, bool decomp, VolFile.ExplodeProgressCallback callback) { string decompDir = Path.Combine(dirPath, VolFile.DecompDir); foreach (VolEntryInfo inf in dirEntries) { string localName = Path.Combine(dirPath, inf.name); if (inf.children != null) { Directory.CreateDirectory(localName); ExtractDirectory(inf.children, localName, decomp, callback); } else { volFile.Seek(inf.fileAddress, SeekOrigin.Begin); byte[] data = new byte[inf.size]; volFile.Read(data, 0, (int)inf.size); callback(String.Format("Extracting {0} from {1:x}", inf.name, inf.fileAddress)); File.WriteAllBytes(localName, data); if (inf.isCompressed && decomp) { Directory.CreateDirectory(decompDir); string decompFileName = Path.Combine(decompDir, inf.name); MemoryStream ms = new MemoryStream(data, false); GZipInputStream gzIn = new GZipInputStream(ms); callback(String.Format("Decompressing {0}", inf.name)); using (FileStream decompFile = new FileStream(decompFileName, FileMode.Create, FileAccess.Write)) { byte[] buffer = new byte[8192]; StreamUtils.Copy(gzIn, decompFile, buffer); } } } } }