Ejemplo n.º 1
0
        public static void Main(string[] args)
        {
            bool   showHelp       = false;
            string currentProject = null;
            bool   littleEndian   = true;

            var options = new OptionSet()
            {
                {
                    "h|help",
                    "show this message and exit",
                    v => showHelp = v != null
                },
                {
                    "l|little-endian",
                    "operate in little-endian mode",
                    v => littleEndian = v != null ? true : littleEndian
                },
                {
                    "b|big-endian",
                    "operate in big-endian mode",
                    v => littleEndian = v != null ? false : littleEndian
                },
                {
                    "p|project=",
                    "override current project",
                    v => currentProject = v
                },
            };

            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 != 0 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            Console.WriteLine("Loading project...");

            var manager = ProjectData.Manager.Load(currentProject);

            if (manager.ActiveProject == null)
            {
                Console.WriteLine("Nothing to do: no active project loaded.");
                return;
            }

            var project = manager.ActiveProject;
            var hashes  = manager.LoadLists(
                "*.filelist",
                s => s.HashFileName(),
                s => s.ToLowerInvariant());

            var installPath = project.InstallPath;
            var listsPath   = project.ListsPath;

            if (installPath == null)
            {
                Console.WriteLine("Could not detect install path.");
                return;
            }
            else if (listsPath == null)
            {
                Console.WriteLine("Could not detect lists path.");
                return;
            }

            Console.WriteLine("Searching for archives...");
            var inputPaths = new List <string>();

            inputPaths.AddRange(Directory.GetFiles(installPath, "*.000", SearchOption.AllDirectories));

            var outputPaths = new List <string>();

            var fileAlignment = manager.GetSetting <uint>("bigfile_alignment", 0x7FF00000);

            Console.WriteLine("Processing...");
            foreach (var inputPath in inputPaths)
            {
                var outputPath = GetListPath(installPath, inputPath);
                if (outputPath == null)
                {
                    throw new InvalidOperationException();
                }

                Console.WriteLine(outputPath);
                outputPath = Path.Combine(listsPath, outputPath);

                if (outputPaths.Contains(outputPath) == true)
                {
                    throw new InvalidOperationException();
                }

                outputPaths.Add(outputPath);

                var big = new BigFileV1();
                big.LittleEndian  = littleEndian;
                big.FileAlignment = fileAlignment;

                if (File.Exists(inputPath + ".bak") == true)
                {
                    using (var input = File.OpenRead(inputPath + ".bak"))
                    {
                        big.Deserialize(input);
                    }
                }
                else
                {
                    using (var input = File.OpenRead(inputPath))
                    {
                        big.Deserialize(input);
                    }
                }

                var localBreakdown = new Breakdown();

                var names = new List <string>();
                foreach (var nameHash in big.Entries.Select(e => e.NameHash).Distinct())
                {
                    var name = hashes[nameHash];
                    if (name != null)
                    {
                        if (names.Contains(name) == false)
                        {
                            names.Add(name);
                            localBreakdown.Known++;
                        }
                    }

                    localBreakdown.Total++;
                }

                names.Sort();

                Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
                using (var output = new StreamWriter(outputPath))
                {
                    output.WriteLine("; {0}", localBreakdown);

                    foreach (string name in names)
                    {
                        output.WriteLine(name);
                    }
                }
            }
        }
Ejemplo n.º 2
0
        public static void Main(string[] args)
        {
            bool showHelp = false;
            string currentProject = null;
            bool littleEndian = true;

            var options = new OptionSet()
            {
                {
                    "h|help",
                    "show this message and exit",
                    v => showHelp = v != null
                },
                {
                    "l|little-endian",
                    "operate in little-endian mode",
                    v => littleEndian = v != null ? true : littleEndian
                },
                {
                    "b|big-endian",
                    "operate in big-endian mode",
                    v => littleEndian = v != null ? false : littleEndian
                },
                {
                    "p|project=",
                    "override current project",
                    v => currentProject = v
                },
            };

            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 != 0 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            Console.WriteLine("Loading project...");

            var manager = ProjectData.Manager.Load(currentProject);
            if (manager.ActiveProject == null)
            {
                Console.WriteLine("Nothing to do: no active project loaded.");
                return;
            }

            var project = manager.ActiveProject;
            var hashes = manager.LoadLists(
                "*.filelist",
                s => s.HashFileName(),
                s => s.ToLowerInvariant());

            var installPath = project.InstallPath;
            var listsPath = project.ListsPath;

            if (installPath == null)
            {
                Console.WriteLine("Could not detect install path.");
                return;
            }
            else if (listsPath == null)
            {
                Console.WriteLine("Could not detect lists path.");
                return;
            }

            Console.WriteLine("Searching for archives...");
            var inputPaths = new List<string>();
            inputPaths.AddRange(Directory.GetFiles(installPath, "*.000", SearchOption.AllDirectories));

            var outputPaths = new List<string>();

            var fileAlignment = manager.GetSetting<uint>("bigfile_alignment", 0x7FF00000);

            Console.WriteLine("Processing...");
            foreach (var inputPath in inputPaths)
            {
                var outputPath = GetListPath(installPath, inputPath);
                if (outputPath == null)
                {
                    throw new InvalidOperationException();
                }

                Console.WriteLine(outputPath);
                outputPath = Path.Combine(listsPath, outputPath);

                if (outputPaths.Contains(outputPath) == true)
                {
                    throw new InvalidOperationException();
                }

                outputPaths.Add(outputPath);

                var big = new BigFileV1();
                big.LittleEndian = littleEndian;
                big.FileAlignment = fileAlignment;

                if (File.Exists(inputPath + ".bak") == true)
                {
                    using (var input = File.OpenRead(inputPath + ".bak"))
                    {
                        big.Deserialize(input);
                    }
                }
                else
                {
                    using (var input = File.OpenRead(inputPath))
                    {
                        big.Deserialize(input);
                    }
                }

                var localBreakdown = new Breakdown();

                var names = new List<string>();
                foreach (var nameHash in big.Entries.Select(e => e.NameHash).Distinct())
                {
                    var name = hashes[nameHash];
                    if (name != null)
                    {
                        if (names.Contains(name) == false)
                        {
                            names.Add(name);
                            localBreakdown.Known++;
                        }
                    }

                    localBreakdown.Total++;
                }

                names.Sort();

                Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
                using (var output = new StreamWriter(outputPath))
                {
                    output.WriteLine("; {0}", localBreakdown);

                    foreach (string name in names)
                    {
                        output.WriteLine(name);
                    }
                }
            }
        }
Ejemplo n.º 3
0
        public static void Main(string[] args)
        {
            bool verbose = true;
            bool showHelp = false;

            var options = new OptionSet()
            {
                {
                    "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_directory [output_archive]", GetExecutableName());
                Console.WriteLine("Pack directory into an 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, ".000");

            if (Directory.Exists(inputPath) == true)
            {
                string testPath = Path.Combine(inputPath, "bigfile.xml");
                if (File.Exists(testPath) == true)
                {
                    inputPath = testPath;
                }
            }

            var outdir = Path.GetDirectoryName(outputPath);
            if (!Directory.Exists(outdir))
                Directory.CreateDirectory(outdir);

            var entries = new List<MyEntry>();
            var big = new BigFileV1();

            using (var input = File.Open(
                inputPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                var doc = new XPathDocument(input);
                var nav = doc.CreateNavigator();

                var root = nav.SelectSingleNode("/files");

                var _fileAlignment = root.GetAttribute("alignment", "");
                if (string.IsNullOrEmpty(_fileAlignment) == true)
                {
                    throw new FormatException("alignment cannot be null or empty");
                }
                big.FileAlignment = uint.Parse(_fileAlignment, NumberStyles.AllowHexSpecifier);

                var _endian = root.GetAttribute("endian", "");
                switch (_endian.ToLowerInvariant())
                {
                    case "big": big.LittleEndian = false; break;
                    case "little":
                    default: big.LittleEndian = true; break;
                }

                //big.BasePath = root.GetAttribute("basepath", "") ?? "PC-W";

                var nodes = root.Select("entry");
                while (nodes.MoveNext() == true)
                {
                    var node = nodes.Current;

                    var _hash = node.GetAttribute("hash", "");
                    if (string.IsNullOrEmpty(_hash) == true)
                    {
                        throw new FormatException("entry hash cannot be null or empty");
                    }

                    var _locale = node.GetAttribute("locale", "");
                    if (string.IsNullOrEmpty(_locale) == true)
                    {
                        throw new FormatException("entry locale cannot be null or empty");
                    }

                    var path = node.Value;
                    if (string.IsNullOrEmpty(path) == true)
                    {
                        throw new FormatException("entry path cannot be null or empty");
                    }

                    if (Path.IsPathRooted(path) == false)
                    {
                        path = Path.Combine(Path.GetDirectoryName(inputPath), path);
                        path = Path.GetFullPath(path);
                    }

                    entries.Add(new MyEntry()
                    {
                        NameHash = uint.Parse(_hash, NumberStyles.AllowHexSpecifier),
                        UncompressedSize = 0,
                        Offset = 0,
                        Locale = uint.Parse(_locale, NumberStyles.AllowHexSpecifier),
                        CompressedSize = 0,
                        Path = path,
                    });
                }
            }

            uint? currentBigFile = null;
            Stream data = null;

            var headerSize = (uint)BigFileV1.EstimateHeaderSize(entries.Count);
            var firstOffset = headerSize / 2048;

            var maxBlocksPerFile = big.FileAlignment / 2048;
            
            var globalOffset = 0u;
            var localOffset = firstOffset;

            var entryBigFile = 0u;

            foreach (var entry in entries)
            {
                if (verbose == true)
                {
                    Console.WriteLine(Path.GetFileName(entry.Path));
                }

                using (var input = File.OpenRead(entry.Path))
                {
                    var length = (uint)input.Length;

                    var blockCount = length.Align(2048) / 2048;

                    if (blockCount > maxBlocksPerFile)
                    {
                        Console.WriteLine("'{0}' can't fit in the archive! (writing as much as possible)", entry.Path);
                        blockCount = maxBlocksPerFile;
                        length = blockCount * 2048;
                    }

                    if (localOffset + blockCount > maxBlocksPerFile)
                    {
                        localOffset = 0;
                        globalOffset += maxBlocksPerFile;
                        entryBigFile++;
                    }

                    if (currentBigFile.HasValue == false ||
                        currentBigFile.Value != entryBigFile)
                    {
                        if (data != null)
                        {
                            data.Close();
                            data = null;
                        }

                        currentBigFile = entryBigFile;
                        data = File.Create(Path.ChangeExtension(outputPath,
                            "." + currentBigFile.Value.ToString().PadLeft(3, '0')));
                    }

                    data.Seek(localOffset * 2048, SeekOrigin.Begin);
                    data.WriteFromStream(input, length);

                    entry.UncompressedSize = length;
                    entry.Offset = globalOffset + localOffset;
                    big.Entries.Add(entry);

                    localOffset += blockCount;
                }
            }

            if (data != null)
            {
                data.Close();
            }

            using (var output = File.OpenWrite(Path.ChangeExtension(outputPath,
                        ".000")))
            {
                big.Serialize(output);
            }
        }
Ejemplo n.º 4
0
        public static void Main(string[] args)
        {
            bool   showHelp        = false;
            bool?  extractUnknowns = null;
            bool   overwriteFiles  = false;
            bool   verbose         = true;
            string currentProject  = null;
            bool   littleEndian    = true;

            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
                },
                {
                    "l|little-endian",
                    "operate in little-endian mode",
                    v => littleEndian = v != null ? true : littleEndian
                },
                {
                    "b|big-endian",
                    "operate in big-endian mode",
                    v => littleEndian = v != null ? false : littleEndian
                },
                {
                    "v|verbose",
                    "be verbose",
                    v => verbose = v != null
                },
                {
                    "h|help",
                    "show this message and exit",
                    v => showHelp = v != null
                },
                {
                    "p|project=",
                    "override current project",
                    v => currentProject = v
                },
            };

            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 ||
                Is000(extras[0]) == false)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_file.000 [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";

            string bigPathSuffix;
            var    bigPathBase = GetBasePath(inputPath, out bigPathSuffix);

            var manager = ProjectData.Manager.Load(currentProject);

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

            var big = new BigFileV1();

            big.Endianness    = littleEndian ? Endian.Little : Endian.Big;
            big.FileAlignment = manager.GetSetting <uint>("bigfile_alignment", 0x7FF00000);
            var compressionType = manager.GetSetting <CompressionType>("compression_type", CompressionType.None);

            using (var input = File.OpenRead(inputPath))
            {
                big.Deserialize(input);
            }

            if (big.Entries.Any(e => e.CompressedSize != 0) == true &&
                compressionType == CompressionType.None)
            {
                throw new InvalidOperationException("compressed entries not supported");
            }

            var test = big.Entries.Where(e => e.CompressedSize != 0).ToArray();

            var hashes = manager.LoadLists(
                "*.filelist",
                s => s.HashFileName(),
                s => s.ToLowerInvariant());

            Directory.CreateDirectory(outputPath);

            var settings = new XmlWriterSettings();

            settings.Indent = true;

            using (var xml = XmlWriter.Create(
                       Path.Combine(outputPath, "bigfile.xml"), settings))
            {
                xml.WriteStartDocument();
                xml.WriteStartElement("files");
                xml.WriteAttributeString("endian", big.Endianness == Endian.Little ? "little" : "big");
                xml.WriteAttributeString("alignment", big.FileAlignment.ToString("X8"));

                Stream data             = null;
                uint?  currentBigFile   = null;
                uint?  lastLocale       = null;
                var    maxBlocksPerFile = big.FileAlignment / 2048;
                {
                    long current = 0;
                    long total   = big.Entries.Count;

                    foreach (var entry in big.Entries.OrderBy(e => e.Offset))
                    {
                        current++;

                        var entryBigFile = entry.Offset / maxBlocksPerFile;
                        var entryOffset  = (entry.Offset % maxBlocksPerFile) * 2048;

                        if (currentBigFile.HasValue == false ||
                            currentBigFile.Value != entryBigFile)
                        {
                            if (data != null)
                            {
                                data.Close();
                                data = null;
                            }

                            currentBigFile = entryBigFile;

                            var bigPath = string.Format("{0}.{1}{2}",
                                                        bigPathBase,
                                                        currentBigFile.Value.ToString().PadLeft(3, '0'),
                                                        bigPathSuffix);

                            if (verbose == true)
                            {
                                Console.WriteLine(bigPath);
                            }

                            data = File.OpenRead(bigPath);
                        }

                        string name = hashes[entry.NameHash];
                        if (name == null)
                        {
                            if (extractUnknowns.HasValue == true &&
                                extractUnknowns.Value == false)
                            {
                                continue;
                            }

                            string extension;
                            // detect type
                            {
                                var guess = new byte[64];
                                int read  = 0;

                                if (entry.UncompressedSize > 0)
                                {
                                    if (entry.CompressedSize != 0)
                                    {
                                        data.Seek(entryOffset, SeekOrigin.Begin);

                                        if (compressionType == CompressionType.Zlib)
                                        {
                                            var zlib = new InflaterInputStream(data);
                                            read = zlib.Read(guess, 0, (int)Math.Min(
                                                                 entry.UncompressedSize, guess.Length));
                                        }
                                        else
                                        {
                                            throw new NotSupportedException();
                                        }
                                    }
                                    else
                                    {
                                        data.Seek(entryOffset, SeekOrigin.Begin);
                                        read = data.Read(guess, 0, (int)Math.Min(
                                                             entry.UncompressedSize, guess.Length));
                                    }
                                }

                                extension = FileExtensions.Detect(
                                    guess, Math.Min(guess.Length, read));
                            }

                            name = entry.NameHash.ToString("X8");
                            name = Path.ChangeExtension(name, "." + extension);
                            name = Path.Combine(extension, name);
                            name = Path.Combine("__UNKNOWN", name);
                        }
                        else
                        {
                            if (extractUnknowns.HasValue == true &&
                                extractUnknowns.Value == true)
                            {
                                continue;
                            }

                            name = name.Replace("/", "\\");
                            if (name.StartsWith("\\") == true)
                            {
                                name = name.Substring(1);
                            }
                        }

                        if (entry.Locale == 0xFFFFFFFF)
                        {
                            name = Path.Combine("default", name);
                        }
                        else
                        {
                            name = Path.Combine(entry.Locale.ToString("X8"), name);
                        }

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

                        if (lastLocale.HasValue == false ||
                            lastLocale.Value != entry.Locale)
                        {
                            xml.WriteComment(string.Format(" {0} = {1} ",
                                                           entry.Locale.ToString("X8"),
                                                           ((Big.Locale)entry.Locale)));
                            lastLocale = entry.Locale;
                        }

                        xml.WriteStartElement("entry");
                        xml.WriteAttributeString("hash", entry.NameHash.ToString("X8"));
                        xml.WriteAttributeString("locale", entry.Locale.ToString("X8"));
                        xml.WriteValue(name);
                        xml.WriteEndElement();

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

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

                        using (var output = File.Create(entryPath))
                        {
                            if (entry.UncompressedSize > 0)
                            {
                                if (entry.CompressedSize != 0)
                                {
                                    data.Seek(entryOffset, SeekOrigin.Begin);

                                    if (compressionType == CompressionType.Zlib)
                                    {
                                        using (var temp = data.ReadToMemoryStream(entry.CompressedSize))
                                        {
                                            var zlib = new InflaterInputStream(temp);
                                            output.WriteFromStream(zlib, entry.UncompressedSize);
                                        }
                                    }
                                    else
                                    {
                                        throw new NotSupportedException();
                                    }
                                }
                                else
                                {
                                    data.Seek(entryOffset, SeekOrigin.Begin);
                                    output.WriteFromStream(data, entry.UncompressedSize);
                                }
                            }
                        }
                    }
                }

                if (data != null)
                {
                    data.Close();
                }

                xml.WriteEndElement();
                xml.WriteEndDocument();
                xml.Flush();
            }
        }
Ejemplo n.º 5
0
        public static void Main(string[] args)
        {
            bool showHelp = false;
            bool? extractUnknowns = null;
            bool overwriteFiles = false;
            bool verbose = true;
            string currentProject = null;
            bool littleEndian = true;

            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
                },
                {
                    "l|little-endian",
                    "operate in little-endian mode",
                    v => littleEndian = v != null ? true : littleEndian
                },
                {
                    "b|big-endian",
                    "operate in big-endian mode",
                    v => littleEndian = v != null ? false : littleEndian
                },
                {
                    "v|verbose",
                    "be verbose",
                    v => verbose = v != null
                },
                {
                    "h|help",
                    "show this message and exit",
                    v => showHelp = v != null
                },
                {
                    "p|project=",
                    "override current project",
                    v => currentProject = v
                },
            };

            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 ||
                Is000(extras[0]) == false)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_file.000 [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";

            string bigPathSuffix;
            var bigPathBase = GetBasePath(inputPath, out bigPathSuffix);

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

            var big = new BigFileV1();
            big.LittleEndian = littleEndian;
            big.FileAlignment = manager.GetSetting<uint>("bigfile_alignment", 0x7FF00000);
            var compressionType = manager.GetSetting<CompressionType>("compression_type", CompressionType.None);

            using (var input = File.OpenRead(inputPath))
            {
                big.Deserialize(input);
            }

            if (big.Entries.Any(e => e.CompressedSize != 0) == true &&
                compressionType == CompressionType.None)
            {
                throw new InvalidOperationException("compressed entries not supported");
            }

            var test = big.Entries.Where(e => e.CompressedSize != 0).ToArray();

            var hashes = manager.LoadLists(
                "*.filelist",
                s => s.HashFileName(),
                s => s.ToLowerInvariant());

            Directory.CreateDirectory(outputPath);

            var settings = new XmlWriterSettings();
            settings.Indent = true;

            using (var xml = XmlWriter.Create(
                Path.Combine(outputPath, "bigfile.xml"), settings))
            {
                xml.WriteStartDocument();
                xml.WriteStartElement("files");
                xml.WriteAttributeString("endian", big.LittleEndian == true ? "little" : "big");
                xml.WriteAttributeString("alignment", big.FileAlignment.ToString("X8"));

                Stream data = null;
                uint? currentBigFile = null;
                uint? lastLocale = null;
                var maxBlocksPerFile = big.FileAlignment / 2048;
                {
                    long current = 0;
                    long total = big.Entries.Count;

                    foreach (var entry in big.Entries.OrderBy(e => e.Offset))
                    {
                        current++;

                        var entryBigFile = entry.Offset / maxBlocksPerFile;
                        var entryOffset = (entry.Offset % maxBlocksPerFile) * 2048;

                        if (currentBigFile.HasValue == false ||
                            currentBigFile.Value != entryBigFile)
                        {
                            if (data != null)
                            {
                                data.Close();
                                data = null;
                            }

                            currentBigFile = entryBigFile;

                            var bigPath = string.Format("{0}.{1}{2}",
                                bigPathBase,
                                currentBigFile.Value.ToString().PadLeft(3, '0'),
                                bigPathSuffix);

                            if (verbose == true)
                            {
                                Console.WriteLine(bigPath);
                            }

                            data = File.OpenRead(bigPath);
                        }

                        string name = hashes[entry.NameHash];
                        if (name == null)
                        {
                            if (extractUnknowns.HasValue == true &&
                                extractUnknowns.Value == false)
                            {
                                continue;
                            }

                            string extension;
                            // detect type
                            {
                                var guess = new byte[64];
                                int read = 0;

                                if (entry.UncompressedSize > 0)
                                {
                                    if (entry.CompressedSize != 0)
                                    {
                                        data.Seek(entryOffset, SeekOrigin.Begin);

                                        if (compressionType == CompressionType.Zlib)
                                        {
                                            var zlib = new InflaterInputStream(data);
                                            read = zlib.Read(guess, 0, (int)Math.Min(
                                                entry.UncompressedSize, guess.Length));
                                        }
                                        else
                                        {
                                            throw new NotSupportedException();
                                        }
                                    }
                                    else
                                    {
                                        data.Seek(entryOffset, SeekOrigin.Begin);
                                        read = data.Read(guess, 0, (int)Math.Min(
                                            entry.UncompressedSize, guess.Length));
                                    }
                                }

                                extension = FileExtensions.Detect(
                                    guess, Math.Min(guess.Length, read));
                            }

                            name = entry.NameHash.ToString("X8");
                            name = Path.ChangeExtension(name, "." + extension);
                            name = Path.Combine(extension, name);
                            name = Path.Combine("__UNKNOWN", name);
                        }
                        else
                        {
                            if (extractUnknowns.HasValue == true &&
                                extractUnknowns.Value == true)
                            {
                                continue;
                            }

                            name = name.Replace("/", "\\");
                            if (name.StartsWith("\\") == true)
                            {
                                name = name.Substring(1);
                            }
                        }

                        if (entry.Locale == 0xFFFFFFFF)
                        {
                            name = Path.Combine("default", name);
                        }
                        else
                        {
                            name = Path.Combine(entry.Locale.ToString("X8"), name);
                        }

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

                        if (lastLocale.HasValue == false ||
                            lastLocale.Value != entry.Locale)
                        {
                            xml.WriteComment(string.Format(" {0} = {1} ",
                                entry.Locale.ToString("X8"),
                                ((Big.Locale)entry.Locale)));
                            lastLocale = entry.Locale;
                        }

                        xml.WriteStartElement("entry");
                        xml.WriteAttributeString("hash", entry.NameHash.ToString("X8"));
                        xml.WriteAttributeString("locale", entry.Locale.ToString("X8"));
                        xml.WriteValue(name);
                        xml.WriteEndElement();

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

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

                        using (var output = File.Create(entryPath))
                        {
                            if (entry.UncompressedSize > 0)
                            {
                                if (entry.CompressedSize != 0)
                                {
                                    data.Seek(entryOffset, SeekOrigin.Begin);

                                    if (compressionType == CompressionType.Zlib)
                                    {
                                        using (var temp = data.ReadToMemoryStream(entry.CompressedSize))
                                        {
                                            var zlib = new InflaterInputStream(temp);
                                            output.WriteFromStream(zlib, entry.UncompressedSize);
                                        }
                                    }
                                    else
                                    {
                                        throw new NotSupportedException();
                                    }
                                }
                                else
                                {
                                    data.Seek(entryOffset, SeekOrigin.Begin);
                                    output.WriteFromStream(data, entry.UncompressedSize);
                                }
                            }
                        }
                    }
                }

                if (data != null)
                {
                    data.Close();
                }

                xml.WriteEndElement();
                xml.WriteEndDocument();
                xml.Flush();
            }
        }
Ejemplo n.º 6
0
        public static void Main(string[] args)
        {
            bool verbose = true;
            bool showHelp = false;

            var options = new OptionSet()
            {
                {
                    "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_directory [output_archive]", GetExecutableName());
                Console.WriteLine("Pack directory into an 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, ".000");

            if (Directory.Exists(inputPath) == true)
            {
                string testPath = Path.Combine(inputPath, "bigfile.xml");
                if (File.Exists(testPath) == true)
                {
                    inputPath = testPath;
                }
            }

            var outdir = Path.GetDirectoryName(outputPath);
            if (!Directory.Exists(outdir))
                Directory.CreateDirectory(outdir);

            var entries = new List<MyEntry>();
            var big = new BigFileV1();

            using (var input = File.Open(
                inputPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                var doc = new XPathDocument(input);
                var nav = doc.CreateNavigator();

                var root = nav.SelectSingleNode("/files");

                var _fileAlignment = root.GetAttribute("alignment", "");
                if (string.IsNullOrEmpty(_fileAlignment) == true)
                {
                    throw new FormatException("alignment cannot be null or empty");
                }
                big.FileAlignment = uint.Parse(_fileAlignment, NumberStyles.AllowHexSpecifier);

                var _endian = root.GetAttribute("endian", "");
                switch (_endian.ToLowerInvariant())
                {
                    case "big": big.LittleEndian = false; break;
                    case "little":
                    default: big.LittleEndian = true; break;
                }

                //big.BasePath = root.GetAttribute("basepath", "") ?? "PC-W";

                var nodes = root.Select("entry");
                while (nodes.MoveNext() == true)
                {
                    var node = nodes.Current;

                    var _hash = node.GetAttribute("hash", "");
                    if (string.IsNullOrEmpty(_hash) == true)
                    {
                        throw new FormatException("entry hash cannot be null or empty");
                    }

                    var _locale = node.GetAttribute("locale", "");
                    if (string.IsNullOrEmpty(_locale) == true)
                    {
                        throw new FormatException("entry locale cannot be null or empty");
                    }

                    var path = node.Value;
                    if (string.IsNullOrEmpty(path) == true)
                    {
                        throw new FormatException("entry path cannot be null or empty");
                    }

                    if (Path.IsPathRooted(path) == false)
                    {
                        path = Path.Combine(Path.GetDirectoryName(inputPath), path);
                        path = Path.GetFullPath(path);
                    }

                    entries.Add(new MyEntry()
                    {
                        NameHash = uint.Parse(_hash, NumberStyles.AllowHexSpecifier),
                        UncompressedSize = 0,
                        Offset = 0,
                        Locale = uint.Parse(_locale, NumberStyles.AllowHexSpecifier),
                        CompressedSize = 0,
                        Path = path,
                    });
                }
            }

            uint? currentBigFile = null;
            Stream data = null;

            var headerSize = (uint)BigFileV1.EstimateHeaderSize(entries.Count);
            var firstOffset = headerSize / 2048;

            var maxBlocksPerFile = big.FileAlignment / 2048;

            var globalOffset = 0u;
            var localOffset = firstOffset;

            var entryBigFile = 0u;

            foreach (var entry in entries)
            {
                if (verbose == true)
                {
                    Console.WriteLine(Path.GetFileName(entry.Path));
                }

                using (var input = File.OpenRead(entry.Path))
                {
                    var length = (uint)input.Length;

                    var blockCount = length.Align(2048) / 2048;

                    if (blockCount > maxBlocksPerFile)
                    {
                        Console.WriteLine("'{0}' can't fit in the archive! (writing as much as possible)", entry.Path);
                        blockCount = maxBlocksPerFile;
                        length = blockCount * 2048;
                    }

                    if (localOffset + blockCount > maxBlocksPerFile)
                    {
                        localOffset = 0;
                        globalOffset += maxBlocksPerFile;
                        entryBigFile++;
                    }

                    if (currentBigFile.HasValue == false ||
                        currentBigFile.Value != entryBigFile)
                    {
                        if (data != null)
                        {
                            data.Close();
                            data = null;
                        }

                        currentBigFile = entryBigFile;
                        data = File.Create(Path.ChangeExtension(outputPath,
                            "." + currentBigFile.Value.ToString().PadLeft(3, '0')));
                    }

                    data.Seek(localOffset * 2048, SeekOrigin.Begin);
                    data.WriteFromStream(input, length);

                    entry.UncompressedSize = length;
                    entry.Offset = globalOffset + localOffset;
                    big.Entries.Add(entry);

                    localOffset += blockCount;
                }
            }

            if (data != null)
            {
                data.Close();
            }

            using (var output = File.OpenWrite(Path.ChangeExtension(outputPath,
                        ".000")))
            {
                big.Serialize(output);
            }
        }