示例#1
0
        // Entry for MC
        public static int MC_Main(TextWriter stdout, TextWriter stderr, String args)
        {
            mcInteropMode = true;

            Console.SetOut(stdout);
            Console.SetError(stderr);

            CommandLineArguments cmdargs = new CommandLineArguments(args);
            return InnerMain(cmdargs);
        }
示例#2
0
        // Actual inner that executes commands
        static int InnerMain(CommandLineArguments cmdargs)
        {
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine(Resources.CopyrightNotice);
            Console.ForegroundColor = ConsoleColor.Gray;

            if (cmdargs.Count == 0)
            {
                Console.WriteLine(Resources.NoArgsMessage);
                Console.WriteLine("\nPress any key to continue...");
                Console.ReadKey();
                Console.Clear();

                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine(Resources.CopyrightNotice);
                Console.ForegroundColor = ConsoleColor.Gray;

                while (true)
                {
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.Write("MCU> ");
                    Console.ForegroundColor = ConsoleColor.Gray;
                    CommandLineArguments args = new CommandLineArguments("MCU " + Console.ReadLine());

                    if (args.Count == 0)
                        continue;

                    Int32 code = MCU_Run(args);
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine("Command finished and returned code {0}\n", code);
                    Console.ForegroundColor = ConsoleColor.Gray;
                }
            }
            else
            {
                return MCU_Run(cmdargs);
            }
        }
示例#3
0
        static int Pack(CommandLineArguments cmdargs)
        {
            // Handle no-arg case
            if (cmdargs.Count == 1)
            {
                WriteMessage(MessageType.Error, "Error 904: No arguments detected\n");
                return 904;
            }

            // Handle help request
            if (cmdargs[1].Type == CommandLineArgument.ArgumentType.Option && cmdargs[1].Name == "?")
            {
                Console.WriteLine(Resources.PackHelp);
                return mcInteropMode ? 903 : 0;
            }

            // Define option variables
            Boolean saveState = false;
            Boolean trimArchive = false;
            Boolean lockArchive = false;
            Boolean verbose = false;
            Boolean patch = false;
            String input = null;
            String output = null;

            // Get options and arguments
            for (int i = 1; i < cmdargs.Count; i++)
            {
                if (cmdargs[i].Type == CommandLineArgument.ArgumentType.Argument)
                {
                    if (input == null)
                    {
                        input = cmdargs[i].Name;
                        output = Path.GetDirectoryName(input) + ".mcpak";
                    }
                    else if (input != null)
                    {
                        output = cmdargs[i].Name;
                    }
                }
                else
                {
                    switch (cmdargs[i].Name.ToLower())
                    {
                        case "savestate":
                            saveState = true;
                            break;
                        case "trim":
                            saveState = true;
                            trimArchive = true;
                            break;
                        case "lock":
                            lockArchive = true;
                            break;
                        case "patch":
                            patch = true;
                            break;
                        case "verbose":
                            verbose = true;
                            break;
                    }
                }
            }

            // Validate
            if (input == null)
            {
                WriteMessage(MessageType.Error, "Error 907: Input path not specified!\n");
                return 907;
            }
            if (!File.Exists(input))
            {
                WriteMessage(MessageType.Error, "Error 909: Specified input file does not exist!\n");
                return 909;
            }

            // Pack Resources
            //#if !DEBUG
            try
            {
            //#endif
                // Create Resource Manager
                CharacterResourceManager resmgr = null;

                // Load resource manager according to the input file supplied
                if (Path.GetExtension(input) == ".mcres")
                {
                    resmgr = CharacterResourceManager.FromXML(input);
                    resmgr.FileSystemProxy = new DefaultFileSystemProxy(Path.GetDirectoryName(input));
                }
                else if (Path.GetExtension(input) == ".mcpak")
                {
                    AFSFileSystemProxy proxy = new AFSFileSystemProxy(input);
                    PackageEntry mcresEntry = proxy.Archive.TryGetEntry("character.mcres");

                    if (mcresEntry == null)
                    {
                        WriteMessage(MessageType.Error, "Error 911: Cannot find resource descriptor entry!\n");
                        return 911;
                    }

                    using (ExStream exs = new ExStream())
                    {
                        proxy.Archive.Extract(mcresEntry, exs);
                        exs.Position = 0;
                        resmgr = CharacterResourceManager.FromXML(exs);
                        resmgr.FileSystemProxy = proxy;
                    }
                }
                else if (Path.GetExtension(input) == ".ini")
                {
                    WriteMessage(MessageType.Error, "Error 912: Directly packing Legacy directories is not supported!\n" +
                        "      You may try using LEGACY command on the input file (directory) first.\n" +
                        "      For more information type \"mcu LEGACY /?\"\n");
                    return 912;
                }
                else
                {
                    WriteMessage(MessageType.Error, "Error 913: Input file extension [{0}] not recognized!\n", Path.GetExtension(input));
                    return 913;
                }

                // Load state if needed
                if (saveState)
                {
                    try
                    {
                        Stream stateStream = resmgr.FileSystemProxy.GetSavedStateStream();
                        if (stateStream != null)
                            LoadCharacterFromStream(resmgr, stateStream);
                        else
                        {
                            if (!trimArchive)
                            {
                                WriteMessage(MessageType.Routine, "No saved state found! No state will be saved into the archive!\n");
                                saveState = false;
                            }
                            else
                            {
                                WriteMessage(MessageType.Error, "Error 914: No saved state found! Cannot apply /trim option!\n");
                                return 914;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        if (!trimArchive)
                        {
                            WriteMessage(MessageType.Routine, "No saved state found! No state will be saved into the archive!\n");
                            saveState = false;
                        }
                        else
                        {
                            WriteMessage(MessageType.Error, "Error 914: No saved state found! Cannot apply /trim option!\n");
                            return 914;
                        }
                        throw ex;
                    }
                }

                // Create packager
                CharacterResourcePacker packer = new CharacterResourcePacker(output, resmgr);
                packer.SaveState = saveState;
                packer.LockCharacter = lockArchive;
                packer.OmitUnusedResources = trimArchive;
                packer.IsPatch = patch;

                // Set up verbose mode if needed
                if (verbose)
                {
                    packer.ArchiveGenerator.NotifyDetails = (String s) =>
                        {
                            Console.Write("      {0}", s);
                        };
                }

                // Start making archive
                if (verbose) WriteMessage(MessageType.Routine, "");
                packer.PackResources();
                if (verbose) Console.WriteLine();

                // Report success
                if (!packer.ArchiveGenerator.HasErrors)
                {
                    WriteMessage(MessageType.Routine, "Success!\n");
                    return 0;
                }
                else
                {
                    WriteMessage(MessageType.Routine, "Error 918: Archive generator reported error(s)!\n");
                    return 918;
                }

            //#if !DEBUG
            }
            catch (Exception ex)
            {
                WriteMessage(MessageType.Error, "An exception of type {0} occured!\n" +
                    "      Exception Message: {1}\n" +
                    "      Stack Trace:\n{2}", ex.GetType().Name,
                    ex.Message, ex.StackTrace);
                return 999;
            }
            //#endif
        }
        static int Cleanup(CommandLineArguments cmdargs)
        {
            // Handle no-arg case
            if (cmdargs.Count == 1)
            {
                WriteMessage(MessageType.Error, "Error 904: No arguments detected\n");
                return 904;
            }

            // Handle help request
            if (cmdargs[1].Type == CommandLineArgument.ArgumentType.Option && cmdargs[1].Name == "?")
            {
                Console.WriteLine(Resources.CleanupHelp);
                return mcInteropMode ? 903 : 0;
            }

            String input = null;
            String moveLocation = "mcu.unused";
            Boolean delete = false;
            Boolean noconfirm = false;
            Boolean deepClean = false;
            String[] ignore = new String[] { "mcres", "mcs", "ini" };

            for (int i = 1; i < cmdargs.Count; i++)
            {
                if (cmdargs[i].Type == CommandLineArgument.ArgumentType.Argument)
                    input = cmdargs[i].Name;
                else
                {
                    switch (cmdargs[i].Name.ToLower())
                    {
                        case "move":
                            {
                                if (cmdargs[i].Arguments.Length == 0)
                                {
                                    WriteMessage(MessageType.Error, "Error 905: /move must have a string argument!");
                                    return 905;
                                }

                                moveLocation = cmdargs[i].Arguments[0];
                            }
                            break;
                        case "delete":
                            delete = true;
                            break;
                        case "noconfirm":
                            noconfirm = true;
                            break;
                        case "deepclean":
                            deepClean = true;
                            break;
                        case "ignore":
                            {
                                String[] tmpIgnore = new String[ignore.Length + cmdargs[i].Arguments.Length];
                                Array.Copy(ignore, tmpIgnore, ignore.Length);
                                Array.Copy(cmdargs[i].Arguments, 0, tmpIgnore, ignore.Length, cmdargs[i].Arguments.Length);
                                //ignore = cmdargs[i].Arguments;
                                ignore = tmpIgnore;
                            }
                            break;
                    }
                }
            }

            // validate
            if (input == null)
            {
                WriteMessage(MessageType.Error, "Error 907: Input Path not specified!\n");
                return 907;
            }
            if (!File.Exists(input))
            {
                WriteMessage(MessageType.Error, "Error 909: Input file does not exist!\n");
                return 909;
            }
            if (Path.GetExtension(input).ToLower() != ".mcres")
            {
                WriteMessage(MessageType.Error, "Error 913: Input file not supported!\n");
                return 913;
            }

            // Load Resource manager
            CharacterResourceManager resmgr = CharacterResourceManager.FromXML(input);

            // Get All Files
            String root = Path.GetDirectoryName(input);
            Dictionary<String, Byte> files = new Dictionary<string, byte>(StringComparer.CurrentCultureIgnoreCase);
            foreach (CharaSetGroup csg in resmgr)
                foreach (CharaSet cset in csg)
                    foreach (CharaPart cpart in cset)
                    {
                        if (!files.ContainsKey(cpart.FileName))
                            files.Add(cpart.FileName, 0);
                    }

            // Recursive Lambda =w=
            List<String> unused = new List<string>();
            Dictionary<String, String> hash2name = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
            Dictionary<String, String> relink = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
            SHA256 hasher = SHA256.Create();
            Action<String> processDir = null;
            processDir = (String path) =>
                {
                    if (File.Exists(path))
                    {
                        if (Path.GetExtension(path).Length > 1 && ignore.Contains(Path.GetExtension(path).Substring(1)))
                            return;

                        if (!files.ContainsKey(libWyvernzora.Path.GetRelativePath(path, root)))
                        {
                            unused.Add(libWyvernzora.Path.GetRelativePath(path, root));
                        }
                        else if (deepClean)
                        {
                            String hash = null;
                            using (FileStream fs = new FileStream(path, FileMode.Open))
                                hash = libWyvernzora.HexTools.Byte2String(hasher.ComputeHash(fs)).ToUpper();

                            String relPath = libWyvernzora.Path.GetRelativePath(path, root);
                            if (!hash2name.ContainsKey(hash))
                                hash2name.Add(hash, relPath);
                            else
                            {
                                String identicalFile = hash2name[hash];
                                relink.Add(relPath, identicalFile);
                                unused.Add(relPath);
                            }
                        }
                    }
                    else if (Directory.Exists(path))
                    {
                        if (Path.GetDirectoryName(path).ToLower().StartsWith("mcu."))
                            return;
                        if (StringComparer.CurrentCultureIgnoreCase.Equals(Path.Combine(root, moveLocation), path))
                            return;
                        if (Path.IsPathRooted(moveLocation) && StringComparer.CurrentCultureIgnoreCase.Equals(moveLocation, path))
                            return;

                        foreach (String dir in Directory.GetDirectories(path))
                            processDir(dir);
                        foreach (String file in Directory.GetFiles(path))
                            processDir(file);
                    }
                };

            processDir(root);

            if (unused.Count != 0)
            {
                WriteMessage(MessageType.Routine, "Following files have been detected as unused:\n");
                foreach (String path in unused)
                {
                    Console.WriteLine("      {0}", path);
                }
                Console.WriteLine();
                if (!noconfirm)
                {
                    WriteMessage(MessageType.Routine, "These files will now be {0}, are you sure to proceed? [Y/N]", delete ? "deleted" : "moved");
                    while (true)
                    {
                        String response = Console.ReadLine();
                        if (response.ToUpper().StartsWith("Y")) break;
                        else if (response.ToUpper().StartsWith("N"))
                        {
                            WriteMessage(MessageType.Routine, "Action cancelled by user.\n");
                            return 915;
                        }
                    }
                }

                if (deepClean)
                {
                    foreach (CharaSetGroup csg in resmgr)
                        foreach (CharaSet cset in csg)
                            foreach (CharaPart cpart in cset)
                            {
                                if (relink.ContainsKey(cpart.FileName))
                                    cpart.FileName = relink[cpart.FileName];
                            }

                    using (FileStream fs = new FileStream(input, FileMode.Create))
                    {
                        XmlWriter xw = XmlTextWriter.Create(fs, new XmlWriterSettings()
                        {
                            Encoding = Encoding.UTF8,
                            Indent = true,
                            IndentChars = "\t"
                        });

                        resmgr.ToXml(xw);
                        xw.Flush();
                    }
                }

                if (!Path.IsPathRooted(moveLocation))
                    moveLocation = Path.Combine(root, moveLocation);

                foreach (String path in unused)
                {
                    String fname = Path.Combine(root, path);
                    if (delete)
                    {
                        File.Delete(fname);
                    }
                    else
                    {
                        String newPath = Path.Combine(moveLocation, path);
                        if (File.Exists(newPath))
                            File.Delete(newPath);
                        if (!Directory.Exists(Path.GetDirectoryName(newPath)))
                            Directory.CreateDirectory(Path.GetDirectoryName(newPath));
                        File.Move(fname, newPath);
                    }
                }

                WriteMessage(MessageType.Routine, "Success!\n");
                return 0;
            }
            else
            {
                WriteMessage(MessageType.Routine, "Resource set is already clean, nothing needs to be done.\n");
                return 0;
            }
        }
示例#5
0
        static int Legacy(CommandLineArguments cmdargs)
        {
            // Handle no-arg case
            if (cmdargs.Count == 1)
            {
                WriteMessage(MessageType.Error, "Error 904: No arguments detected\n");
                return 904;
            }

            // Handle help request
            if (cmdargs[1].Type == CommandLineArgument.ArgumentType.Option && cmdargs[1].Name == "?")
            {
                Console.WriteLine(Resources.LegacyHelp);
                return mcInteropMode ? 903 : 0; // MC Interop Mode does not support /? flag and treats it as an error
            }

            // Define arg variables
            Boolean ini = true;
            Int32 width = -1;
            Int32 height = -1;
            String charname = null;
            String dir = null;

            #region Arg Validation
            // Check all args
            for (int i = 1; i < cmdargs.Count; i++)
            {
                if (cmdargs[i].Type == CommandLineArgument.ArgumentType.Argument)
                    dir = cmdargs[i].Name;
                else
                {
                    switch (cmdargs[i].Name.ToLower())
                    {
                        case "ini":
                            {
                                Boolean tmp;

                                if (cmdargs[i].Arguments.Length == 0
                                    || !Boolean.TryParse(cmdargs[i].Arguments[0], out tmp))
                                {
                                    WriteMessage(MessageType.Error, "Error 905: /ini must have a boolean argument!\n");
                                    return 905;
                                }

                                ini = tmp;
                            }
                            break;
                        case "width":
                            {
                                Int32 tmp;

                                if (cmdargs[i].Arguments.Length == 0
                                    || !Int32.TryParse(cmdargs[i].Arguments[0], out tmp))
                                {
                                    WriteMessage(MessageType.Error, "Error 905: /width must have an integer argument!\n");
                                    return 905;
                                }

                                width = tmp;
                            }
                            break;
                        case "height":
                            {
                                Int32 tmp;

                                if (cmdargs[i].Arguments.Length == 0
                                    || !Int32.TryParse(cmdargs[i].Arguments[0], out tmp))
                                {
                                    WriteMessage(MessageType.Error, "Error 905: /height must have an integer argument!\n");
                                    return 905;
                                }

                                height = tmp;
                            }
                            break;
                        case "charname":
                            {
                                if (cmdargs[i].Arguments.Length == 0)
                                {
                                    WriteMessage(MessageType.Error, "Error 905: /charaname must have a string argument!\n");
                                    return 905;
                                }

                                charname = cmdargs[i].Arguments[0];
                            }
                            break;
                    }
                }
            }
            #endregion

            // Validate Input
            if (ini && Path.GetFileName(dir) == "character.ini")
            {
                dir = Path.GetDirectoryName(dir);
            }
            if (!ini && (height < 0 || width < 0))
            {
                WriteMessage(MessageType.Error, "Error 906: When /ini:false, /height and /width must be specified\n");
                return 906;
            }
            if (dir == null)
            {
                WriteMessage(MessageType.Error, "Error 906: Directory to load was not specified!\n");
                return 907;
            }
            if (!Directory.Exists(dir) || (ini && !File.Exists(Path.Combine(dir, "character.ini"))))
            {
                WriteMessage(MessageType.Error, "Error 906: Specified directory (or character.ini) does not exist!\n");
                return 909;
            }

            // Start working on the task
            CharaxDirHelper dirHelper = null;
            if (ini)
                dirHelper = new CharaxDirHelper(Path.Combine(dir, "character.ini"));
            else
                dirHelper = new CharaxDirHelper(dir, width, height);

            // Set charname if it was specified
            if (charname != null)
                dirHelper.CharaName = charname;

            // Write the descriptor
            dirHelper.GenerateDescriptor(Path.Combine(dir, "character.mcres"));

            // Report success
            WriteMessage(MessageType.Routine, "Success!\n");
            return 0;
        }
示例#6
0
 static int Help(CommandLineArguments cmdargs)
 {
     Console.WriteLine(Resources.Help);
     return mcInteropMode ? 903 : 0;
 }
示例#7
0
 static int MCU_Run(CommandLineArguments cmdargs)
 {
     if (cmdargs[0].Type == CommandLineArgument.ArgumentType.Option)
     {
         WriteMessage(MessageType.Error, "Error 901: Command cannot be a command line option\n");
         return 901;
     }
     try
     {
         String command = cmdargs[0].Name.ToUpper();
         switch (command)
         {
             case "HELP":
                 return Help(cmdargs);
             case "LEGACY":
                 return Legacy(cmdargs);
             case "PACK":
                 return Pack(cmdargs);
             case "CLEANUP":
                 return Cleanup(cmdargs);
             case "VERIFY":
                 return Verify(cmdargs);
             case "DEPLOY":
                 return Deploy(cmdargs);
             default:
                 {
                     WriteMessage(MessageType.Error, "Error 902: Command not recognized!\n");
                     return 902;
                 }
         }
     }
     catch (Exception ex)
     {
         Console.Error.WriteLine("An exception of type {0} occured!", ex.GetType().Name);
         Console.Error.WriteLine("Exception Message: {0}", ex.Message);
         Console.Error.WriteLine("========== Stack Trace ==========\n{0}", ex.StackTrace);
         return 999;
     }
 }
示例#8
0
        static int Deploy(CommandLineArguments cmdargs)
        {
            // Handle no-arg case
            if (cmdargs.Count == 1)
            {
                WriteMessage(MessageType.Error, "Error 904: No arguments detected\n");
                return 904;
            }

            // Handle help request
            if (cmdargs[1].Type == CommandLineArgument.ArgumentType.Option && cmdargs[1].Name == "?")
            {
                Console.WriteLine(Resources.DeployHelp);
                return mcInteropMode ? 903 : 0;
            }

            // Get Options
            String deployRoot = "patches\\%PATCHNAME%";
            String targetPath = null;
            String patchPath = null;
            Boolean merge = false;
            Boolean update = false;
            Boolean checkhash = false;
            CollisionHandling collisionMode = CollisionHandling.Prompt;

            #region Get Options

            for (int i = 1; i < cmdargs.Count; i++)
            {
                if (cmdargs[i].Type == CommandLineArgument.ArgumentType.Argument)
                {
                    if (patchPath == null)
                        patchPath = cmdargs[i].Name;
                    else if (targetPath == null)
                        targetPath = cmdargs[i].Name;
                }
                else
                {
                    switch (cmdargs[i].Name.ToLower())
                    {
                        case "deployroot":
                            {
                                if (cmdargs[i].Arguments.Length == 0)
                                {
                                    WriteMessage(MessageType.Error, "Error 905: /deployroot must have a string argument!\n");
                                    return 905;
                                }

                                deployRoot = cmdargs[i].Arguments[0];
                            }
                            break;
                        case "merge":
                            {
                                merge = true;
                            }
                            break;
                        case "update":
                            {
                                update = true;
                            }
                            break;
                        case "checkhash":
                            checkhash = true;
                            break;
                        case "collision":
                            {
                                if (cmdargs[i].Arguments.Length == 0)
                                {
                                    WriteMessage(MessageType.Error, "Error 905: /collision must have a string argument!\n");
                                    return 905;
                                }

                                switch (cmdargs[i].Arguments[0].ToLower())
                                {
                                    case "prompt":
                                        collisionMode = CollisionHandling.Prompt;
                                        break;
                                    case "error":
                                        collisionMode = CollisionHandling.Error;
                                        break;
                                    case "overwrite":
                                        collisionMode = CollisionHandling.Overwrite;
                                        break;
                                    case "rename":
                                        collisionMode = CollisionHandling.Rename;
                                        break;
                                    case "skip":
                                        collisionMode = CollisionHandling.Skip;
                                        break;
                                    default:
                                        {
                                            WriteMessage(MessageType.Error, "Error 905: /collision argument \"{0}\" not recognized!\n", cmdargs[i].Arguments[0]);
                                            return 905;
                                        }
                                }

                            }
                            break;
                    }
                }
            }
            #endregion

            // Verify
            if (patchPath == null)
            { WriteMessage(MessageType.Error, "Error 907: Pacth file not specified!\n"); return 907; }
            if (targetPath == null)
            { WriteMessage(MessageType.Error, "Error 908: Target path not specified!\n"); return 908; }
            if (!File.Exists(patchPath))
            { WriteMessage(MessageType.Error, "Error 909: Specified patch file does not exist!\n"); return 909; }
            if (!File.Exists(targetPath))
            { WriteMessage(MessageType.Error, "Error 910: Specified target resource descriptor does not exist!\n"); return 910; }
            if (Path.GetExtension(targetPath).ToLower() != ".mcres")
            { WriteMessage(MessageType.Error, "Error 916: Target file not supported!\n"); return 916; }
            if (Path.GetExtension(patchPath).ToLower() != ".mcpak")
            { WriteMessage(MessageType.Error, "Error 913: Patch file not supported!\n"); return 913; }

            // Change settings
            if (merge) deployRoot = "";
            if (update) collisionMode = CollisionHandling.Overwrite;

            // load both resources
            // load target resource manager
            CharacterResourceManager target = CharacterResourceManager.FromXML(targetPath);
            String targetRoot = Path.GetDirectoryName(targetPath);
            target.FileSystemProxy = new DefaultFileSystemProxy(targetRoot);

            // load patch resource manager
            CharacterResourceManager patch = null;
            AFSFileSystemProxy afsproxy = new AFSFileSystemProxy(patchPath);
            using (ExStream descrs = new ExStream())
            {
                PackageEntry mcres = afsproxy.Archive.TryGetEntry("character.mcres");
                if (mcres == null)
                { WriteMessage(MessageType.Error, "Error 911: Cannot find descriptor in patch archive!\n"); return 911; }
                afsproxy.Archive.Extract(mcres, descrs);
                descrs.Position = 0;
                patch = CharacterResourceManager.FromXML(descrs);
            }
            // load patch filename mapping if it exists
            Dictionary<String, String> fileNameMap = null;
            PackageEntry fmapentry = afsproxy.Archive.TryGetEntry(".patch");
            if (fmapentry != null)
            {
                fileNameMap = new Dictionary<string, string>();
                XmlDocument fmapdoc = new XmlDocument();
                using (ExStream fmaps = new ExStream())
                {
                    afsproxy.Archive.Extract(fmapentry, fmaps);
                    fmaps.Position = 0;
                    fmapdoc.Load(fmaps);
                }
                foreach (XmlNode mapNode in fmapdoc.SelectNodes("FileNameMap/Mapping"))
                {
                    String hashed = mapNode.Attributes["key"].InnerText;
                    String original = mapNode.InnerText;

                    fileNameMap.Add(hashed, original);
                }
            }
            patch.FileSystemProxy = afsproxy;

            // finalize deploy root
            deployRoot = deployRoot.Replace("%PATCHNAME%", Path.GetFileNameWithoutExtension(patchPath));

            // Virtual Extraction to identify possible problems
            Dictionary<PackageEntry, String> extractionPaths = new Dictionary<PackageEntry, string>();
            Dictionary<String, String> relink = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
            List<PackageEntry> problems = new List<PackageEntry>();

            foreach (PackageEntry entry in afsproxy.Archive.Entries)
            {
                if (entry.Name.ToLower() == ".patch" || entry.Name.ToLower() == ".lock") continue;
                String ext = Path.GetExtension(entry.Name).ToLower();
                if (ext == ".mcres" || ext == ".mcs") continue;

                String entryName = (fileNameMap != null && fileNameMap.ContainsKey(entry.Name)) ?
                    fileNameMap[entry.Name] : entry.Name;

                String relExtrPath = Path.Combine(deployRoot, entryName);
                String absExtrPath = Path.Combine(targetRoot, relExtrPath);

                if (File.Exists(absExtrPath))
                {
                    if (checkhash)
                    {
                        // Files collided, verify whether thay are identical
                        String targetHash = GetSHA(absExtrPath);
                        String patchHash = null;
                        using (ExStream exs = new ExStream())
                        {
                            afsproxy.Archive.Extract(entry, exs);
                            patchHash = GetSHA(exs);
                        }

                        if (targetHash == patchHash)
                            continue;  // Both files are identical, skip extraction
                    }

                    // they are not identical or checkhash disabled... need to do something
                    CollisionHandling handling = collisionMode;
                    if (collisionMode == CollisionHandling.Prompt)
                    {
                        WriteMessage(MessageType.Routine, "File collision detected:\n");
                        Console.WriteLine("        Target: {0}", relExtrPath);
                        Console.WriteLine("        Patch: {0}", entryName);
                        Console.WriteLine("        1) Error\n        2) Rename\n        3) Overwrite\n        4) Skip");
                        while (true)
                        {
                            Console.Write("        Action:");
                            Int32 result;
                            if (!Int32.TryParse(Console.ReadLine(), out result)) continue;
                            if (result < 1 || result > 4) continue;
                            handling = (CollisionHandling)result;
                            if (handling == CollisionHandling.Error) // if user choses error, no need to prompt for further collisions
                                collisionMode = CollisionHandling.Error;
                            break;
                        }
                    }

                    // handle collision
                    switch (handling)
                    {
                        case CollisionHandling.Error:
                            {
                                problems.Add(entry);
                                continue;
                            }
                        case CollisionHandling.Rename:
                            {
                                Int32 cid = 1;
                                string nfname = relExtrPath;
                                while (true)
                                {
                                    nfname = Path.Combine(Path.GetDirectoryName(relExtrPath),
                                        String.Format("{0}({1}){2}", Path.GetFileNameWithoutExtension(relExtrPath),
                                        cid++, Path.GetExtension(relExtrPath)));
                                    if (!File.Exists(Path.Combine(targetRoot, nfname))) break;
                                }

                                extractionPaths.Add(entry, nfname);
                                relink.Add(entry.Name, nfname);
                                continue;
                            }
                        case CollisionHandling.Overwrite:
                            extractionPaths.Add(entry, relExtrPath);
                            relink.Add(entry.Name, relExtrPath);
                            continue;
                        case CollisionHandling.Skip:
                            relink.Add(entry.Name, relExtrPath);
                            continue;
                    }

                }
                else
                {
                    extractionPaths.Add(entry, relExtrPath);
                    relink.Add(entry.Name, relExtrPath);
                }
            }

            if (problems.Count != 0)
            {
                WriteMessage(MessageType.Error, "{0} Error(s) have been detected!\n", problems.Count);
                foreach (PackageEntry entry in problems)
                {
                    String entryName = (fileNameMap != null && fileNameMap.ContainsKey(entry.Name)) ?
                    fileNameMap[entry.Name] : entry.Name;

                    String relExtrPath = Path.Combine(deployRoot, entryName);
                    Console.WriteLine("        Collision with {0}", relExtrPath);
                }
                WriteMessage(MessageType.Error, "Error 917: Deployment failed due to unresolved file collisions!\n");

                return 917;
            }

            // Extract Files
            foreach (KeyValuePair<PackageEntry, String> extr in extractionPaths)
            {
                String path = Path.Combine(targetRoot, extr.Value);
                afsproxy.Archive.ExtractSingle(extr.Key, path);
            }

            // Merge Color Presets
            foreach (String colorg in patch.Presets.Keys)
            {
                if (!target.Presets.ContainsKey(colorg))
                    target.Presets.Add(colorg, patch.Presets[colorg]);
            }

            // Merge Character Part Records
            foreach (CharaSetGroup patchsg in patch)
            {
                // Skip empty set groups
                if (patchsg.Count == 0) continue;

                // Get target chara set group
                CharaSetGroup targetsg = target.GetGroupByName(patchsg.Name);
                if (targetsg == null)
                {
                    // if it doesn't exist, create it
                    targetsg = new CharaSetGroup(patchsg.Name, patchsg.Multiselect);
                    target.Add(targetsg);
                }

                // foreach chara set in the patch group
                foreach (CharaSet patchset in patchsg)
                {
                    // Get target chara set
                    CharaSet targetset = targetsg.GetSetByName(patchset.Name);

                    // if the set exists and update flag is up, delete it
                    if (targetset != null && update)
                    {
                        targetsg.Remove(targetset);
                        targetset = new CharaSet(patchset.Name);
                    }
                    else if (targetset != null)
                    { // if the set exists but update flag is not up, rename the new set
                        Int32 index = 1;

                        Match m = Regex.Match(patchset.Name, "(?<name>.+?)(?<index>[0-9]+)");
                        if (m.Success)
                        {
                            index = Int32.Parse(m.Result("${index}"));
                            patchset.Name = m.Result("${name}");
                        }

                        while (true)
                        {
                            if (targetsg.GetSetByName(patchset.Name + (index++).ToString()) == null)
                                break;
                        }
                        targetset = new CharaSet(patchset.Name + (index).ToString());
                    }
                    else
                    { // if it doesn't exist, create it
                        targetset = new CharaSet(patchset.Name);
                    }

                    // Add target set to target
                    targetsg.Add(targetset);

                    // copy all parts taking file renaming into consideration
                    foreach (CharaPart patchpart in patchset)
                    {
                        String filePath = relink[patchpart.FileName];

                        targetset.Add(new CharaPart(patchpart.UnadjustedLayer, filePath, patchpart.ColorScheme));
                    }
                }

                targetsg.SortSets();
            }

            if (File.Exists(Path.ChangeExtension(targetPath, "bak")))
                File.Delete(Path.ChangeExtension(targetPath, "bak"));
            File.Move(targetPath, Path.ChangeExtension(targetPath, "bak"));
            using (XmlWriter xw = XmlTextWriter.Create(targetPath,
                new XmlWriterSettings() { Indent = true, IndentChars = "\t", Encoding = Encoding.UTF8 }))
            {
                target.ToXml(xw);
                xw.Flush();
            }

            WriteMessage(MessageType.Routine, "Success!\n");
            return 0;
        }
示例#9
0
        static int Verify(CommandLineArguments cmdargs)
        {
            // Handle no-arg case
            if (cmdargs.Count == 1)
            {
                WriteMessage(MessageType.Error, "Error 904: No arguments detected\n");
                return 904;
            }

            // Handle help request
            if (cmdargs[1].Type == CommandLineArgument.ArgumentType.Option && cmdargs[1].Name == "?")
            {
                Console.WriteLine(Resources.VerifyHelp);
                return mcInteropMode ? 903 : 0;
            }

            // Get options
            String input = null;
            Boolean delMissing = false;
            Boolean noconfirm = false;

            for (int i = 1; i < cmdargs.Count; i++)
            {
                if (cmdargs[i].Type == CommandLineArgument.ArgumentType.Argument)
                    input = cmdargs[i].Name;
                else
                {
                    switch (cmdargs[i].Name.ToLower())
                    {
                        case "deletemissing":
                            delMissing = true;
                            break;
                        case "noconfirm":
                            noconfirm = true;
                            break;
                    }
                }
            }

            // validate
            if (input == null)
            {
                WriteMessage(MessageType.Error, "Error 907: Input Path not specified!\n");
                return 907;
            }
            if (!File.Exists(input))
            {
                WriteMessage(MessageType.Error, "Error 909: Input file does not exist!\n");
                return 909;
            }
            if (Path.GetExtension(input).ToLower() != ".mcres")
            {
                WriteMessage(MessageType.Error, "Error 913: Input file not supported!\n");
                return 913;
            }

            // Load Resource manager
            CharacterResourceManager resmgr = CharacterResourceManager.FromXML(input);
            String root = Path.GetDirectoryName(input);

            // Verify
            List<CharaSet> missing = new List<CharaSet>();
            foreach (CharaSetGroup csg in resmgr)
                foreach (CharaSet cset in csg)
                    foreach (CharaPart cpart in cset)
                    {
                        if (!File.Exists(Path.Combine(root, cpart.FileName)))
                        {
                            missing.Add(cset);
                            break;
                        }
                    }

            if (missing.Count != 0)
            {
                // print out missing list
                WriteMessage(MessageType.Routine, "Mising files have been detected in following sets:\n");
                foreach (CharaSet cset in missing)
                {
                    Console.WriteLine("      {0}/{1}", cset.Parent.Name, cset.Name);
                }

                // confirmation
                if (delMissing && !noconfirm)
                {
                    WriteMessage(MessageType.Routine, "These sets will now be deleted, are you sure to proceed? [Y/N]");
                    while (true)
                    {
                        String response = Console.ReadLine();
                        if (response.ToUpper().StartsWith("Y")) break;
                        else if (response.ToUpper().StartsWith("N"))
                        {
                            WriteMessage(MessageType.Routine, "Action cancelled by user.\n");
                            return 915;
                        }
                    }
                }

                if (delMissing)
                {
                    foreach (CharaSet set in missing)
                    {
                        set.Parent.Remove(set);
                    }

                    using (FileStream fs = new FileStream(input, FileMode.Create))
                    {
                        XmlWriter xw = XmlTextWriter.Create(fs, new XmlWriterSettings()
                        {
                            Encoding = Encoding.UTF8,
                            Indent = true,
                            IndentChars = "\t"
                        });

                        resmgr.ToXml(xw);
                        xw.Flush();
                    }

                }

                WriteMessage(MessageType.Routine, "Success!\n");
            }
            else
            {
                WriteMessage(MessageType.Routine, "No missing files have been detected!\n");
            }
            return 0;
        }