Esempio n. 1
0
        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);
                }
            }
        }