public GT3DemoVol(string file) { volFile = new FileStream(file, FileMode.Open, FileAccess.Read); byte[] intArray = new byte[4]; volFile.Seek(8, SeekOrigin.Begin); volFile.Read(intArray, 0, 4); uint headerSize = BitConverter.ToUInt32(intArray, 0); volFile.Seek(0, SeekOrigin.Begin); byte[] header = new byte[headerSize]; volFile.Read(header, 0, (int)headerSize); Debug.Assert((header[0] == 'R') && (header[1] == 'o') && (header[2] == 'F') && (header[3] == 'S')); MemoryStream ms = new MemoryStream(header, false); ms.Seek(0xc, SeekOrigin.Begin); BinaryReader br = new BinaryReader(ms, Encoding.UTF8); uint rootEntryData = br.ReadUInt32(); if ((rootEntryData & Flags.Directory) != Flags.Directory) { Console.Error.WriteLine("{0} is an invalid VOL", file); volFile.Close(); return; } uint nameOffset = (rootEntryData & Flags.TurnOffFlags); rootVolEntry = new VolEntryInfo(); rootVolEntry.size = 0; rootVolEntry.fileAddress = 0xc; rootVolEntry.name = ReadNullTermName(br, nameOffset); rootVolEntry.children = ParseDirectory(br); }
public GT3Vol(string file) { volFile = new FileStream(file, FileMode.Open, FileAccess.Read); byte[] magic = new byte[4]; volFile.Read(magic, 0, magic.Length); // if this is a demo vol if ((magic[0] == 'R') && (magic[1] == 'o') && (magic[2] == 'F') && (magic[3] == 'S')) { isDemoVol = true; compressedFlag = 0x2; directoryFlag = 0x1; } // this is 'RoFS' but bitwise not-ted else if ((magic[0] == 0xAD) && (magic[1] == 0x90) && (magic[2] == 0xB9) && (magic[3] == 0xAC)) { isDemoVol = false; compressedFlag = 0x02000000; directoryFlag = 0x01000000; } else { volFile.Close(); throw new FileLoadException("This isn't a GT3 VOL"); } allFlags = compressedFlag | directoryFlag; turnOffFlags = ~allFlags; byte[] intArray = new byte[4]; volFile.Seek(8, SeekOrigin.Begin); volFile.Read(intArray, 0, 4); uint headerSize = BitConverter.ToUInt32(intArray, 0); volFile.Seek(0, SeekOrigin.Begin); byte[] header = new byte[headerSize]; volFile.Read(header, 0, (int)headerSize); MemoryStream ms = new MemoryStream(header, false); BinaryReader br = new BinaryReader(ms); br.BaseStream.Seek(0xc, SeekOrigin.Begin); if (!isDemoVol) { //volFile.Read(intArray, 0, 4); //uint namesOffset = BitConverter.ToUInt32(intArray, 0) + 1; uint namesOffset = br.ReadUInt32(); uint namesSize = headerSize - namesOffset; for (uint i = namesOffset; i < headerSize; ++i) { header[i] = (byte)~header[i]; } br.BaseStream.Seek(0x14, SeekOrigin.Begin); } uint rootEntryData = br.ReadUInt32(); if ((rootEntryData & directoryFlag) != directoryFlag) { Console.Error.WriteLine("{0} is an invalid VOL", file); volFile.Close(); throw new FileLoadException("Don't recognize this type of GT3.VOL"); } uint nameOffset = rootEntryData & turnOffFlags; rootVolEntry = new VolEntryInfo(); rootVolEntry.size = 0; rootVolEntry.fileAddress = isDemoVol ? 0xcu : 0x14u; rootVolEntry.name = ReadNullTermName(br, nameOffset); rootVolEntry.children = ParseDirectory(br); }
private List <VolEntryInfo> ParseDirectory(BinaryReader br) { int numEntries = br.ReadInt32(); List <VolEntryInfo> entryInfo = new List <VolEntryInfo>(numEntries); long currentFileOffset = br.BaseStream.Position; for (int i = 0; i < numEntries; ++i) { uint entryOffset = (uint)br.BaseStream.Position; uint entry = br.ReadUInt32(); uint entryFlag = entry & allFlags; uint entryPointer = entry & turnOffFlags; // directory entries are offsets to data about the entries // the flags for directories etc are in this data, not the entries themselves Debug.Assert(entryFlag == 0); // parent entry if (entryPointer < currentFileOffset) { continue; } uint offsetValue = GetValueAtOffset(br, entryPointer); uint offsetFlag = offsetValue & allFlags; uint offsetPosition = offsetValue & turnOffFlags; string entryName = ReadNullTermName(br, offsetPosition); VolEntryInfo volEntry = new VolEntryInfo(); volEntry.children = null; volEntry.name = entryName; volEntry.isCompressed = false; volEntry.entryAddress = entryOffset; volEntry.fileInfoAddress = entryPointer; if (offsetFlag == directoryFlag) { volEntry.size = 0; long preParsePos = br.BaseStream.Position; br.BaseStream.Seek(entryPointer + 4, SeekOrigin.Begin); volEntry.children = ParseDirectory(br); br.BaseStream.Seek(preParsePos, SeekOrigin.Begin); } else if (offsetFlag == compressedFlag) // compressed file (gzip) { // high byte 2 = gzip compressed file (lower 3 bytes, name offset) // first entry = file data offset // second entry = decompressed size // third entry = compressed size (ie the size of the data in the vol) volEntry.isCompressed = true; long preParsePos = br.BaseStream.Position; br.BaseStream.Seek(entryPointer + 4, SeekOrigin.Begin); uint dataOffset = br.ReadUInt32() * 0x800; volEntry.fileAddress = dataOffset; br.ReadUInt32(); // decompressed size, not needed volEntry.size = br.ReadUInt32(); br.BaseStream.Seek(preParsePos, SeekOrigin.Begin); } else // entry { Debug.Assert(offsetFlag == 0); long preParsePos = br.BaseStream.Position; br.BaseStream.Seek(entryPointer + 4, SeekOrigin.Begin); uint dataOffset = br.ReadUInt32() * 0x800; volEntry.fileAddress = dataOffset; volEntry.size = br.ReadUInt32(); if (isDemoVol) { // the demo has 4 entries for both compressed and normal files br.ReadUInt32(); } br.BaseStream.Seek(preParsePos, SeekOrigin.Begin); } entryInfo.Add(volEntry); } return(entryInfo); }
private List <VolEntryInfo> ParseDirectory(BinaryReader br) { int numEntries = br.ReadInt32(); List <VolEntryInfo> entryInfo = new List <VolEntryInfo>(numEntries); long currentFileOffset = br.BaseStream.Position; for (int i = 0; i < numEntries; ++i) { uint entryOffset = (uint)br.BaseStream.Position; uint entry = br.ReadUInt32(); uint entryFlag = (entry & Flags.AllFlags); uint entryPointer = entry & ~Flags.TurnOffFlags; // directory entries are offsets to data about the entries // the flags for directories etc are in this data, not the entries themselves Debug.Assert(entryFlag == 0); // parent entry if (entryPointer < currentFileOffset) { continue; } uint offsetValue = GetValueAtOffset(br, entryPointer); uint offsetFlag = offsetValue & Flags.AllFlags; uint offsetPosition = offsetValue & Flags.TurnOffFlags; string entryName = ReadNullTermName(br, offsetPosition); VolEntryInfo volEntry = new VolEntryInfo(); volEntry.children = null; volEntry.name = entryName; volEntry.isCompressed = false; volEntry.entryAddress = entryOffset; volEntry.fileInfoAddress = entryPointer; switch (offsetFlag) { case 1: // directory { volEntry.size = 0; long preParsePos = br.BaseStream.Position; br.BaseStream.Seek(entryPointer + 4, SeekOrigin.Begin); volEntry.children = ParseDirectory(br); br.BaseStream.Seek(preParsePos, SeekOrigin.Begin); } break; case 2: // compressed file (gzip) case 0: // uncompressed file { // files - // first entry = file data offset // second entry = decompressed size // third entry = compressed size (ie the size of the data in the vol) volEntry.isCompressed = (offsetFlag == 2); long preParsePos = br.BaseStream.Position; br.BaseStream.Seek(entryPointer + 4, SeekOrigin.Begin); uint dataOffset = br.ReadUInt32() * 0x800; volEntry.fileAddress = dataOffset; br.ReadUInt32(); // decompressed size, not needed volEntry.size = br.ReadUInt32(); br.BaseStream.Seek(preParsePos, SeekOrigin.Begin); } break; default: { Debug.Assert(false); } break; } entryInfo.Add(volEntry); } return(entryInfo); }