public static void WriteFileNameHash(this Stream stream, FileNameHash hash)
 {
     stream.WriteValueU32(hash.A, Endian.Big);
     stream.WriteValueU32(hash.B, Endian.Big);
     stream.WriteValueU32(hash.C, Endian.Big);
     stream.WriteValueU32(hash.D, Endian.Big);
 }
Beispiel #2
0
 public static void WriteFileNameHash(this Stream stream, FileNameHash hash)
 {
     stream.WriteValueU32(hash.A, Endian.Big);
     stream.WriteValueU32(hash.B, Endian.Big);
     stream.WriteValueU32(hash.C, Endian.Big);
     stream.WriteValueU32(hash.D, Endian.Big);
 }
Beispiel #3
0
 public int CompareTo(object obj)
 {
     if (obj is FileNameHash)
     {
         FileNameHash temp = (FileNameHash)obj;
         string       a    = this.ToString();
         string       b    = obj.ToString();
         return(a.CompareTo(b));
     }
     throw new ArgumentException();
 }
        public static void Main(string[] args)
        {
            bool showHelp = false;
            bool extractUnknowns = true;
            bool overwriteFiles = false;
            bool verbose = false;

            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
                },
                {
                    "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_sfar [output_dir]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

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

            var manager = ProjectData.Manager.Load();
            if (manager.ActiveProject == null)
            {
                Console.WriteLine("Warning: no active project loaded.");
            }
            var hashes = manager.LoadLists(
                "*.filelist",
                FileNameHash.Compute,
                s => s.Replace("\\", "/"));

            using (var input = File.OpenRead(inputPath))
            {
                var sfx = new SFXArchiveFile();
                sfx.Deserialize(input);

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

                if (sfx.CompressionScheme != SFXArchive.CompressionScheme.None &&
                    sfx.CompressionScheme != SFXArchive.CompressionScheme.Lzma &&
                    sfx.CompressionScheme != SFXArchive.CompressionScheme.Lzx)
                {
                    Console.WriteLine("Unsupported compression scheme!");
                    return;
                }

                var inputBlock = new byte[sfx.MaximumBlockSize];
                var outputBlock = new byte[sfx.MaximumBlockSize];

                var hashesFromFile = new Dictionary<FileNameHash, string>();

                // todo: figure out what the file name is
                var fileNameListNameHash = new FileNameHash(
                    new byte[] { 0xB5, 0x50, 0x19, 0xCB, 0xF9, 0xD3, 0xDA, 0x65, 0xD5, 0x5B, 0x32, 0x1C, 0x00, 0x19, 0x69, 0x7C, });
                var fileNameListEntry = sfx.Entries
                    .FirstOrDefault(e =>
                        e.NameHash == fileNameListNameHash);
                if (fileNameListEntry != null)
                {
                    using (var temp = new MemoryStream())
                    {
                        DecompressEntry(
                            sfx, fileNameListEntry,
                            input, inputBlock,
                            temp, outputBlock);
                        temp.Position = 0;

                        var reader = new StreamReader(temp);
                        while (reader.EndOfStream == false)
                        {
                            var line = reader.ReadLine();
                            hashesFromFile.Add(FileNameHash.Compute(line), line);
                        }
                    }
                }

                foreach (var entry in sfx.Entries)
                {
                    current++;

                    var entryName = hashes[entry.NameHash];
                    
                    if (entryName == null)
                    {
                        if (hashesFromFile.ContainsKey(entry.NameHash) == true)
                        {
                            entryName = hashesFromFile[entry.NameHash];
                        }
                    }

                    if (entryName == null)
                    {
                        if (extractUnknowns == false)
                        {
                            continue;
                        }

                        entryName = entry.NameHash.ToString();
                        entryName = Path.Combine("__UNKNOWN", entryName);
                    }
                    else
                    {
                        entryName = entryName.Replace("/", "\\");
                        if (entryName.StartsWith("\\") == true)
                        {
                            entryName = entryName.Substring(1);
                        }
                    }

                    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);
                    }

                    input.Seek(entry.Offset, SeekOrigin.Begin);

                    Directory.CreateDirectory(Path.GetDirectoryName(entryPath));
                    using (var output = File.Create(entryPath))
                    {
                        DecompressEntry(
                            sfx, entry,
                            input, inputBlock,
                            output, outputBlock);
                    }
                }
            }
        }