Esempio n. 1
0
        public static void Main(string[] args)
        {
            bool showHelp       = false;
            bool overwriteFiles = false;
            bool verbose        = false;

            var options = new OptionSet()
            {
                { "o|overwrite", "overwrite existing files", v => overwriteFiles = 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_arc [output_dir]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            var inputPath  = Path.GetFullPath(extras[0]);
            var outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, null) + "_unpack";

            using (var input = File.OpenRead(inputPath))
            {
                const uint signature = 0x50414B00; // 'PAK\0'
                var        magic     = input.ReadValueU32(Endian.Big);
                if (magic != signature)
                {
                    throw new FormatException();
                }
                const Endian endian = Endian.Little;

                var headerSize = input.ReadValueU32(endian);
                var dataSize   = input.ReadValueU32(endian);

                if (headerSize + dataSize != input.Length)
                {
                    Console.WriteLine("[warning] Pak file size inconsistent!");
                }

                var rootNameLength = input.ReadValueU8();
                if (rootNameLength != 0)
                {
                    throw new FormatException();
                }

                var rootIsDirectory = input.ReadValueB8();
                if (rootIsDirectory == false)
                {
                    throw new FormatException();
                }
                var rootFileCount = input.ReadValueU32(endian);

                var root  = new PakDirectory();
                var files = new List <PakFile>();

                var stack = new Stack <PakStackDirectory>();
                stack.Push(new PakStackDirectory(root, 0, rootFileCount));

                while (stack.Count > 0)
                {
                    var item  = stack.Pop();
                    var dir   = item.Directory;
                    var i     = item.Index;
                    var count = item.Count;

                    for (; i < count; i++)
                    {
                        var nameLength  = input.ReadValueU8();
                        var name        = input.ReadString(nameLength, true, Encoding.UTF8);
                        var isDirectory = input.ReadValueB8();
                        if (isDirectory == false)
                        {
                            var fileOffset = input.ReadValueU32(endian);
                            var fileSize   = input.ReadValueU32(endian);
                            var fileHash   = input.ReadValueU32(endian);
                            var file       = new PakFile()
                            {
                                Parent = dir,
                                Name   = name,
                                Offset = fileOffset,
                                Size   = fileSize,
                                Hash   = fileHash,
                            };
                            dir.Files.Add(file);
                            files.Add(file);
                        }
                        else
                        {
                            var subdir = new PakDirectory()
                            {
                                Parent = dir,
                                Name   = name,
                            };
                            dir.Subdirectories.Add(subdir);
                            var subdirFileCount = input.ReadValueU32(endian);
                            stack.Push(new PakStackDirectory(dir, i + 1, count));
                            stack.Push(new PakStackDirectory(subdir, 0, subdirFileCount));
                            break;
                        }
                    }
                }

                var dataMagic = input.ReadValueU32(Endian.Big);
                if (dataMagic != 0x44415441) // 'DATA'
                {
                    Console.WriteLine("[warning] Pak header did not end with 'DATA'! Files will likely be corrupt.");
                }

                if (headerSize != input.Position)
                {
                    Console.WriteLine("[warning] Header size inconsistent! Files will likely be corrupt.");
                }

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

                foreach (var file in files)
                {
                    current++;

                    var name = file.Name;
                    var dir  = file.Parent;
                    while (dir != null && dir.Name != null)
                    {
                        name = Path.Combine(dir.Name, name);
                        dir  = dir.Parent;
                    }

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

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

                    var entryDirectory = Path.GetDirectoryName(entryPath);
                    if (entryDirectory != null)
                    {
                        Directory.CreateDirectory(entryDirectory);
                    }

                    input.Position = headerSize + file.Offset;
                    using (var output = File.Create(entryPath))
                    {
                        output.WriteFromStream(input, file.Size);
                    }
                }
            }
        }
Esempio n. 2
0
 public PakStackDirectory(PakDirectory directory, uint index, uint count)
 {
     this.Directory = directory;
     this.Index     = index;
     this.Count     = count;
 }