public static void Main(string[] args) { bool showHelp = false; bool overwriteFiles = false; string cdkey = null; string extensionFilter = null; var options = new OptionSet() { { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null }, { "cdkey=", "cdkey for use with DLC archives\n(in format #####-#####-#####-#####)", v => cdkey = v }, { "e|extension=", "only extract files of this extension", v => extensionFilter = v }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extras; try { extras = 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 (extras.Count < 1 || extras.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_dzip [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, null); outputPath = Path.GetFullPath(outputPath); var uncompressed = new byte[0x10000]; bool filtering = string.IsNullOrEmpty(extensionFilter) == false; using (var input = File.Open(inputPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var pkg = new PackageFile(); pkg.DeserializeWithCdKey(input, cdkey); long current = 0; long total = pkg.Entries.Count; foreach (var entry in pkg.Entries) { current++; var entryPath = Path.Combine(outputPath, entry.Name); if (overwriteFiles == false && File.Exists(entryPath) == true) { continue; } if (filtering == true && Path.GetExtension(entryPath) != extensionFilter) { continue; } Console.WriteLine("[{0}/{1}] {2}", current, total, entry.Name); var entryDirectory = Path.GetDirectoryName(entryPath); if (entryDirectory == null) { throw new InvalidOperationException(); } Directory.CreateDirectory(entryDirectory); input.Seek(entry.Offset, SeekOrigin.Begin); var blocks = (int)((entry.UncompressedSize + 0xFFFF) >> 16); // .Align(0x10000) / 0x10000; var offsets = new long[blocks + 1]; for (int i = 0; i < offsets.Length; i++) { offsets[i] = entry.Offset + input.ReadValueU32(); } offsets[blocks] = entry.Offset + entry.CompressedSize; using (var output = File.Create(entryPath)) { long left = entry.UncompressedSize; for (int i = 0; i < blocks; i++) { var compressed = new byte[offsets[i + 1] - offsets[i + 0]]; input.Seek(offsets[i], SeekOrigin.Begin); input.Read(compressed, 0, compressed.Length); int read = Lzf.Decompress(compressed, uncompressed); if (i + 1 < blocks && read != uncompressed.Length) { throw new InvalidOperationException(); } output.Write(uncompressed, 0, (int)Math.Min(left, read)); left -= read; } } File.SetLastWriteTime(entryPath, entry.TimeStamp); } } }