Ejemplo n.º 1
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
        }
Ejemplo n.º 2
0
        private void Menu_AddMCPatch(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = String.Format("{0}|*.mcpak", Localization.LocalizationDictionary.Instance["EXT_MCPAK"]);
            if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.Cancel)
            {
                AFSFileSystemProxy proxy = new AFSFileSystemProxy(ofd.FileName);

                CharacterResourceManager patch;

                using (ExStream descriptor = new ExStream())
                {
                    PackageEntry entry = proxy.Archive.TryGetEntry("character.mcres");
                    proxy.Archive.Extract(entry, descriptor);
                    descriptor.Position = 0;

                    patch = CharacterResourceManager.FromXML(descriptor);
                }

                patch.FileSystemProxy = proxy;

                resourceManager.Merge(patch);

                ReloadResourceManager();
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Loads a character packed into AFS file
        /// File extension doesn't have to be AFS
        /// </summary>
        /// <param name="path"></param>
        public void LoadCharacterResourcesAFS(String path)
        {
            using (CharaBlocker cb = new CharaBlocker(this))
            {
                AFSFileSystemProxy proxy = new AFSFileSystemProxy(path);

                using (ExStream descriptor = new ExStream())
                {
                    PackageEntry entry = proxy.Archive.TryGetEntry("character.mcres");
                    proxy.Archive.Extract(entry, descriptor);
                    descriptor.Position = 0;

                    resourceManager = CharacterResourceManager.FromXML(descriptor);
                }

                resourceManager.FileSystemProxy = proxy;
                resourceManager.AllowChange = proxy.Archive.TryGetEntry(".lock") == null;


                ReloadResourceManager();
                ResetSelection();
                UpdateColorProcessorList();
                cmbColorProcessors.SelectedIndex = 0;

                // If there is a saved state, restore it as well
                // Here we usa a FileSystemProxy because we have no idea whether
                // the state is stored on a file or a package
                Stream state = resourceManager.FileSystemProxy.GetSavedStateStream();
                if (state != null)
                {
                    LoadCharacterFromStream(state, false);
                    state.Dispose();
                }
                else
                {
                    ResetSelection();
                    resourceManager.Processors.Clear();
                    UpdateColorProcessorList();
                }

                // Reflect color processors on the UI
                UpdateColorProcessorList();

                // Reload Chara Set List
                ReloadPropertyListView((CharaSetGroup)cmbCharaProp.SelectedItem);

                // Generate Layer Adjustment values
                foreach (CharaSetGroup csg in resourceManager)
                {
                    if (!csg.Multiselect) continue;
                    GenerateLayerAdjustments(csg);
                }

                // Maintain CharaBlocker instance
                cb.DummyMethod();
                
            }

            miTools.Enabled = false;
            UpdateCharacterPreviewAsync();
            DebugHelper.DebugPrint("Successfully loaded AFS: {0}", resourceManager.Name);
        }
Ejemplo n.º 4
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;
        }