Beispiel #1
0
        public static void Main(string[] args)
        {
            bool   showHelp          = false;
            bool   extractUnknowns   = true;
            bool   onlyUnknowns      = false;
            bool   extractFiles      = true;
            string filterPattern     = null;
            bool   overwriteFiles    = false;
            bool   validateChecksums = false;
            bool   verbose           = false;

            var options = new OptionSet()
            {
                { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null },
                { "nf|no-files", "don't extract files", v => extractFiles = v == null },
                { "nu|no-unknowns", "don't extract unknown files", v => extractUnknowns = v == null },
                { "ou|only-unknowns", "only extract unknown files", v => onlyUnknowns = v != null },
                { "f|filter=", "only extract files using pattern", v => filterPattern = v },
                { "c|validate-checksums", "validate checksums of extracted files", v => validateChecksums = v != null },
                { "v|verbose", "be verbose", v => verbose = v != null },
                { "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_a [output_dir]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Unpack files from a packed archive.");
                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) + "_unpack";

            Regex filter = null;

            if (string.IsNullOrEmpty(filterPattern) == false)
            {
                filter = new Regex(filterPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
            }

            if (verbose == true)
            {
                Console.WriteLine("Loading project...");
            }

            var manager = ProjectData.Manager.Load();

            if (manager.ActiveProject == null)
            {
                Console.WriteLine("Warning: no active project loaded.");
            }

            using (var input = File.OpenRead(inputPath))
            {
                IArchiveFile archive;

                if (ArchiveFile.IsValid(input) == true)
                {
                    archive = new ArchiveFile();
                }
                else if (Antibirth.FileFormats.ArchiveFile.IsValid(input) == true)
                {
                    archive = new Antibirth.FileFormats.ArchiveFile();
                }
                else
                {
                    throw new NotSupportedException();
                }

                archive.Deserialize(input);

                var hashes = manager.LoadListsFileNames();

                if (extractFiles == true)
                {
                    var sortedEntries = archive.Entries.OrderBy(e => e.Offset).ToArray();

                    if (sortedEntries.Length > 0)
                    {
                        if (verbose == true)
                        {
                            Console.WriteLine("Unpacking files...");
                        }

                        long current = 0;
                        long total   = sortedEntries.Length;
                        var  padding = total.ToString(CultureInfo.InvariantCulture).Length;

                        var duplicates = new Dictionary <ulong, int>();

                        foreach (var entry in sortedEntries)
                        {
                            current++;

                            string entryName;
                            if (hashes.Contains(entry.NameHash) == false)
                            {
                                if (extractUnknowns == false)
                                {
                                    continue;
                                }

                                entryName = entry.NameHash.ToString("X16");
                                entryName = Path.Combine("__UNKNOWN", entryName + ".unknown");
                            }
                            else
                            {
                                if (onlyUnknowns == true)
                                {
                                    continue;
                                }

                                entryName = hashes[entry.NameHash];
                                entryName = FilterEntryName(entryName);
                            }

                            if (duplicates.ContainsKey(entry.NameHash) == true)
                            {
                                var number = duplicates[entry.NameHash]++;
                                var e      = Path.GetExtension(entryName);
                                var nn     =
                                    Path.ChangeExtension(
                                        Path.ChangeExtension(entryName, null) + "__DUPLICATE_" +
                                        number.ToString(CultureInfo.InvariantCulture),
                                        e);
                                entryName = Path.Combine("__DUPLICATE", nn);
                            }
                            else
                            {
                                duplicates[entry.NameHash] = 0;
                            }

                            if (filter != null &&
                                filter.IsMatch(entryName) == false)
                            {
                                continue;
                            }

                            var entryPath = Path.Combine(outputPath, entryName);
                            if (overwriteFiles == false &&
                                File.Exists(entryPath) == true)
                            {
                                continue;
                            }

                            if (verbose == true)
                            {
                                Console.WriteLine(
                                    "[{0}/{1}] {2}",
                                    current.ToString(CultureInfo.InvariantCulture).PadLeft(padding),
                                    total,
                                    entryName);
                            }

                            var entryParent = Path.GetDirectoryName(entryPath);
                            if (string.IsNullOrEmpty(entryParent) == false)
                            {
                                Directory.CreateDirectory(entryParent);
                            }

                            input.Seek(entry.Offset, SeekOrigin.Begin);
                            using (var data = entry.Read(input, archive))
                            {
                                if (archive.HasChecksums == true && validateChecksums == true)
                                {
                                    var bytes    = data.ToArray();
                                    var checksum = ArchiveFile.ComputeChecksum(bytes, 0, bytes.Length);
                                    if (checksum != entry.Checksum)
                                    {
                                        Console.WriteLine(
                                            "checksum mismatch for {0}: {1:X} vs {2:X}",
                                            entryName,
                                            entry.Checksum,
                                            checksum);
                                    }
                                }

                                using (var output = File.Create(entryPath))
                                {
                                    output.WriteFromStream(data, entry.Length);
                                }
                            }
                        }
                    }
                }
            }
        }