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);
                    }
                }
            }
        }
Exemple #3
0
        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})");
        }