private static IFileContainer HandleNestedPack( Stream input, Queue <QueuedFile> fileQueue, int id, string name, IFileContainer parent) { var basePosition = input.Position; var packFile = new PackFile(); packFile.Deserialize(input); var container = new NestedPack() { Id = id, BasePath = Path.Combine(parent.BasePath, name), Parent = parent, }; var hasIds = packFile.Entries.Any(e => e.RawId != 0); var entryCount = packFile.Entries.Count; for (int i = 0; i < entryCount; i++) { var entry = packFile.Entries[i]; uint nextEntryOffset = i + 1 < entryCount ? packFile.Entries[i + 1].Offset : packFile.TotalSize; uint entrySize = nextEntryOffset - entry.Offset; fileQueue.Enqueue(new QueuedFile() { Id = i, Parent = container, PackRawId = hasIds == false ? (uint?)null : entry.RawId, DataOffset = basePosition + entry.Offset, DataSize = entrySize, }); } return(container); }
public static void Main(string[] args) { bool verbose = false; bool showHelp = false; var options = new OptionSet() { { "v|verbose", "be verbose (list files)", v => verbose = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extra; try { extra = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extra.Count < 1 || extra.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_pack [output_directory]", GetExecutableName()); Console.WriteLine("Unpack specified archive."); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string inputPath = extra[0]; string outputBasePath = extra.Count > 1 ? extra[1] : Path.ChangeExtension(inputPath, null) + "_unpacked"; Directory.CreateDirectory(outputBasePath); using (var input = File.OpenRead(inputPath)) { var header = new PackFile(); header.Deserialize(input); var entryCount = header.Entries.Count; for (int i = 0; i < entryCount; i++) { var outputPath = Path.Combine(outputBasePath, $"{i}"); uint entryOffset = header.Entries[i].Offset; uint nextEntryOffset = i + 1 >= entryCount ? header.TotalSize : header.Entries[i + 1].Offset; uint entrySize = nextEntryOffset - entryOffset; input.Position = entryOffset; var extension = FileDetection.Guess(input, (int)entrySize, entrySize); outputPath = Path.ChangeExtension(outputPath, extension); if (verbose == true) { Console.WriteLine(outputPath); } input.Position = entryOffset; using (var output = File.Create(outputPath)) { output.WriteFromStream(input, entrySize); } } } }
public static void Main(string[] args) { bool showHelp = false; var options = new OptionSet() { { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extra; try { extra = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extra.Count < 3 || extra.Count > 3 || showHelp == true || ParseArgument(extra[1], out uint directoryId) == false || ParseArgument(extra[2], out long offset) == false) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_FILETABLE <dir> <offset>", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string inputPath = extra[0]; FileTableFile table; using (var input = File.OpenRead(inputPath)) { table = new FileTableFile(); table.Deserialize(input); } var directoryIndex = table.Directories.FindIndex(de => de.Id == directoryId); if (directoryIndex < 0) { Console.WriteLine($"Directory ID {directoryId} not found."); return; } var directory = table.Directories[directoryIndex]; var blockSize = FileTableFile.BaseDataBlockSize << directory.DataBlockSize; var fileIndex = directory.Files.FindIndex( fe => offset >= fe.DataBlockOffset * blockSize && offset < (fe.DataBlockOffset * blockSize) + fe.DataSize); if (fileIndex < 0) { Console.WriteLine($"Offset does not appear to correspond to file within directory ID {directoryId}."); return; } var inputBasePath = Path.GetDirectoryName(inputPath); var binPath = Path.Combine(inputBasePath, $"{directory.Id:X4}.BIN"); var file = directory.Files[fileIndex]; Console.WriteLine($"Directory ID: {directory.Id}"); Console.WriteLine($" File ID: {file.Id}"); if (file.DataSize < 8) { return; } long dataPosition; int level = 2; using (var input = File.OpenRead(binPath)) { dataPosition = file.DataBlockOffset * blockSize; while (true) { input.Position = dataPosition; var fileMagic = input.ReadValueU32(Endian.Little); if (fileMagic != PackFile.Signature && fileMagic.Swap() != PackFile.Signature) { break; } input.Position = dataPosition; var packFile = new PackFile(); packFile.Deserialize(input); int i; long foundPosition = -1; for (i = 0; i < packFile.Entries.Count; i++) { var entryOffset = packFile.Entries[i].Offset; var nextEntryOffset = i + 1 < packFile.Entries.Count ? packFile.Entries[i + 1].Offset : packFile.TotalSize; var startPosition = dataPosition + entryOffset; var endPosition = dataPosition + nextEntryOffset; if (offset >= startPosition && offset < endPosition) { foundPosition = startPosition; break; } } if (foundPosition < 0) { break; } Console.WriteLine($"{"".PadLeft(level)}Pack file index: {i}"); dataPosition = foundPosition; level++; } } var relativePosition = offset - dataPosition; Console.WriteLine($"{"".PadLeft(level)}Offset: 0x{relativePosition:X} ({relativePosition})"); }