Esempio n. 1
0
        private static MemoryStream ReadFileData(
            HogFile hog, Hog.FileEntry entry, Stream input)
        {
            var data = new MemoryStream();

            ReadFileData(hog, entry, input, data);
            data.Position = 0;
            return(data);
        }
Esempio n. 2
0
        private static void ReadFileData(
            HogFile hog,
            Hog.FileEntry entry,
            Stream input,
            Stream output)
        {
            if (hog.Files.Contains(entry) == false)
            {
                throw new ArgumentException("bad entry", "entry");
            }

            if (entry.Size == -1)
            {
                throw new ArgumentException("cannot read file with size of -1", "entry");
            }

            if (entry.Unknown5 != -2 || entry.AttributeId == -1)
            {
                throw new ArgumentException("strange entry");
            }

            if (entry.AttributeId < 0 || entry.AttributeId >= hog.Attributes.Count)
            {
                throw new ArgumentException("entry pointing to invalid metadata", "entry");
            }

            if ((hog.Attributes[entry.AttributeId].Flags & 1) == 1) // entry is unused
            {
                throw new ArgumentException("entry referencing unused attribute", "entry");
            }

            input.Seek(entry.Offset, SeekOrigin.Begin);
            var attribute = hog.Attributes[entry.AttributeId];

            if (attribute.UncompressedSize != 0)
            {
                using (var temp = input.ReadToMemoryStream(entry.Size))
                {
                    var zlib = new InflaterInputStream(temp);
                    output.WriteFromStream(zlib, attribute.UncompressedSize);
                }
            }
            else
            {
                output.WriteFromStream(input, entry.Size);
            }
        }
Esempio n. 3
0
        public static void Main(string[] args)
        {
            bool   showHelp        = false;
            bool?  extractUnknowns = null;
            bool   overwriteFiles  = false;
            bool   verbose         = true;
            string pattern         = null;

            var options = new OptionSet()
            {
                { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null },
                {
                    "nu|no-unknowns", "don't extract unknown files",
                    v => extractUnknowns = v != null ? false : extractUnknowns
                },
                {
                    "ou|only-unknowns", "only extract unknown files",
                    v => extractUnknowns = v != null ? true : extractUnknowns
                },
                { "v|verbose", "be verbose", v => verbose = v != null },
                { "f|filter=", "match files using pattern", v => pattern = 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_file.hogg [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) + "_unpack";

            Regex regex = null;

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

            using (var input = File.OpenRead(inputPath))
            {
                var hog = new HogFile();
                hog.Deserialize(input);

                var dataList      = new Dictionary <int, byte[]>();
                var dataListEntry = hog.Files
                                    .SingleOrDefault(e => e.AttributeId == 0 && e.Size != -1);
                if (dataListEntry != null)
                {
                    using (var data = ReadFileData(hog, dataListEntry, input))
                    {
                        if (data.ReadValueU32(hog.Endian) != 0)
                        {
                            throw new FormatException();
                        }

                        var count = data.ReadValueS32(hog.Endian);
                        if (count < 0)
                        {
                            throw new FormatException();
                        }

                        for (int i = 0; i < count; i++)
                        {
                            var length = data.ReadValueU32(hog.Endian);
                            dataList.Add(i, data.ReadBytes((int)length));
                        }
                    }
                }

                using (var data = new MemoryStream(hog.DataListJournal))
                {
                    var journal = new JournalFile()
                    {
                        Endian = hog.Endian,
                    };
                    journal.Deserialize(data);

                    foreach (var entry in journal.Entries)
                    {
                        if (entry.Action == Journal.Action.Add)
                        {
                            dataList[entry.TargetId] = (byte[])entry.Data.Clone();
                        }
                        else if (entry.Action == Journal.Action.Remove)
                        {
                            if (dataList.Remove(entry.TargetId) == false)
                            {
                                throw new InvalidOperationException();
                            }
                        }
                        else
                        {
                            throw new InvalidOperationException();
                        }
                    }
                }

                var consumedAttributes = new List <int>();
                var files = hog.Files
                            .Where(e => e.Size != -1 && e.AttributeId != 0)
                            .ToArray();

                long current = 0;
                long total   = files.Count();

                var names = new Dictionary <int, string>();

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

                    if (entry.Unknown5 != -2 || entry.AttributeId == -1)
                    {
                        throw new InvalidOperationException();
                    }

                    if (entry.AttributeId < 0 || entry.AttributeId >= hog.Attributes.Count)
                    {
                        throw new InvalidOperationException();
                    }

                    if ((hog.Attributes[entry.AttributeId].Flags & 1) == 1) // entry is unused
                    {
                        throw new InvalidOperationException();
                    }

                    if (consumedAttributes.Contains(entry.AttributeId) == true)
                    {
                        throw new InvalidOperationException();
                    }

                    consumedAttributes.Add(entry.AttributeId);

                    var attribute = hog.Attributes[entry.AttributeId];

                    string name;

                    if (dataList.ContainsKey(attribute.NameId) == false)
                    {
                        name = Path.Combine("__UNKNOWN", attribute.NameId.ToString(CultureInfo.InvariantCulture));
                    }
                    else
                    {
                        if (names.ContainsKey(attribute.NameId) == true)
                        {
                            name = names[attribute.NameId];
                        }
                        else
                        {
                            using (var temp = new MemoryStream(dataList[attribute.NameId]))
                            {
                                name = temp.ReadStringZ(Encoding.UTF8);
                                names.Add(attribute.NameId, name);
                            }
                        }

                        name = name.Replace('/', Path.DirectorySeparatorChar);
                        if (name.StartsWith(Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture)) == true)
                        {
                            name = name.Substring(1);
                        }
                    }

                    if (regex != null && regex.IsMatch(name) == false)
                    {
                        continue;
                    }

                    var entryPath = Path.Combine(outputPath, name);

                    if (overwriteFiles == false &&
                        File.Exists(entryPath) == true)
                    {
                        continue;
                    }

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

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

                    using (var output = File.Create(entryPath))
                    {
                        ReadFileData(hog, entry, input, output);
                    }
                }
            }
        }