예제 #1
0
        private IEnumerable <TaskFunc> GetItemDownloadTask(Repository.Repository.Item item)
        {
            var taskFuncs = new List <TaskFunc>();
            var tempPath  = TempHelpers.getUniqueTempPath();

            switch (item.Kind)
            {
            case Repository.Repository.ItemKind.Hmod:
                var modPath = Path.Combine(Program.BaseDirectoryExternal, "user_mods", item.FileName);
                if (File.Exists(modPath))
                {
                    File.Delete(modPath);
                }

                if (Directory.Exists(modPath))
                {
                    Directory.Delete(modPath, true);
                }

                if (item.Extract)
                {
                    taskFuncs.AddRange(new TaskFunc[] {
                        IOTasks.DirectoryCreate(modPath),
                        IOTasks.DirectoryCreate(tempPath),
                        WebClientTasks.DownloadFile(item.URL, Path.Combine(tempPath, item.FileName)),
                        ArchiveTasks.ExtractArchive(Path.Combine(tempPath, item.FileName), modPath),
                        IOTasks.DirectoryDelete(tempPath, true)
                    });
                }
                else
                {
                    taskFuncs.Add(WebClientTasks.DownloadFile(item.URL, modPath));
                }

                break;

            case Repository.Repository.ItemKind.Game:
                taskFuncs.AddRange(new TaskFunc[] {
                    IOTasks.DirectoryCreate(tempPath),
                    WebClientTasks.DownloadFile(item.URL, Path.Combine(tempPath, item.FileName)),
                    (Tasker tasker, object sync) =>
                    {
                        var taskerForms = tasker.GetSpecificViews <TaskerForm>().ToArray();
                        MainForm.StaticRef.AddGames(new string[] {
                            Path.Combine(tempPath, item.FileName)
                        }, parentForm: taskerForms.Length > 0 ? (Form)taskerForms[0] : (Form)parentForm);
                        return(Conclusion.Success);
                    },
                    IOTasks.DirectoryDelete(tempPath, true)
                });
                break;
            }
            return(taskFuncs);
        }
예제 #2
0
        public static TaskFunc ProcessNand(string nandDump, NandTasks task)
        {
            return((Tasker tasker, Object sync) =>
            {
                return TempHelpers.doWithTempFolder((tempFolder) =>
                {
                    NandTasks[] validTasks = { NandTasks.DumpNand, NandTasks.DumpSystemPartition, NandTasks.DumpUserPartition, NandTasks.FlashSystemPartition, NandTasks.FlashUserPartition };
                    if (!validTasks.Contains(task))
                    {
                        throw new ArgumentOutOfRangeException(Enum.GetName(typeof(NandTasks), task));
                    }

                    if (task == NandTasks.FlashSystemPartition || task == NandTasks.FlashUserPartition)
                    {
                        var extension = new FileInfo(nandDump).Extension.ToLower();

                        if (extension == ".gz" || extension == ".tgz" || extension == ".xz" || extension == ".bz2")
                        {
                            var tempFilename = Path.Combine(tempFolder, "dump.bin");

                            using (var extractor = ArchiveFactory.Open(nandDump))
                                using (var entryStream = extractor.Entries.First().OpenEntryStream())
                                    using (var extractedFile = File.Create(tempFilename))
                                    {
                                        tasker.SetStatus(Resources.ExtractingToTemporaryFolder);
                                        entryStream.CopyTo(extractedFile);
                                        nandDump = tempFilename;
                                    }
                        }
                    }

                    bool isHsqs = false;
                    bool isExtFs = false;
                    bool isTar = false;

                    if (task == NandTasks.FlashSystemPartition && !((isHsqs = Files.CheckFileType.IsSquashFs(nandDump)) || (isExtFs = Files.CheckFileType.IsExtFs(nandDump)) || (isTar = Files.CheckFileType.IsTar(nandDump))))
                    {
                        throw new Exception(Properties.Resources.InvalidHsqs);
                    }


                    if (task == NandTasks.FlashUserPartition)
                    {
                        if (!((isTar = Files.CheckFileType.IsTar(nandDump)) || (isExtFs = Files.CheckFileType.IsExtFs(nandDump))))
                        {
                            throw new Exception(Properties.Resources.InvalidUserDataBackup);
                        }
                    }

                    var nandInfo = Sunxi.NandInfo.GetNandInfo();

                    long partitionSize = 300 * 1024 * 1024;
                    var splitStream = new SplitterStream(Program.debugStreams);
                    string rootfsDevice = $"/dev/{nandInfo.GetRootfsPartition().Device}";
                    string osDecryptedDevice = rootfsDevice;
                    string userDataDevice = $"/dev/{nandInfo.GetDataPartition().Device}";
                    bool hasKeyfile = hakchi.Shell.Execute("[ -f /key-file ]") == 0;

                    if (hasKeyfile)
                    {
                        osDecryptedDevice = "/dev/mapper/root-crypt";
                    }

                    bool systemIsHsqs = hakchi.Shell.ExecuteSimple($"dd if={osDecryptedDevice} bs=1 count=4", 0) == "HSQS";

                    switch (task)
                    {
                    case NandTasks.DumpSystemPartition:
                        if (systemIsHsqs)
                        {
                            partitionSize = long.Parse(hakchi.Shell.ExecuteSimple($"echo $((($(hexdump -e '1/4 \"%u\"' -s $((0x28)) -n 4 {osDecryptedDevice})+0xfff)/0x1000))", throwOnNonZero: true).Trim()) * 4 * 1024;
                        }
                        else
                        {
                            partitionSize = long.Parse(hakchi.Shell.ExecuteSimple($"blockdev --getsize64 {osDecryptedDevice}", throwOnNonZero: true));
                        }
                        break;

                    case NandTasks.FlashSystemPartition:
                        hakchi.Shell.Execute("hakchi umount_base", null, splitStream, splitStream);
                        hakchi.Shell.Execute("umount /newroot");
                        if (hasKeyfile)
                        {
                            hakchi.Shell.Execute("cryptsetup close root-crypt");
                            hakchi.Shell.ExecuteSimple($"cryptsetup open {rootfsDevice} root-crypt --type plain --cipher aes-xts-plain --key-file /key-file", 2000, true);
                        }
                        partitionSize = long.Parse(hakchi.Shell.ExecuteSimple($"blockdev --getsize64 {osDecryptedDevice}", throwOnNonZero: true));
                        break;

                    case NandTasks.DumpUserPartition:
                        hakchi.Shell.Execute("hakchi mount_base", null, null, null, 0, true);
                        partitionSize = long.Parse(hakchi.Shell.ExecuteSimple("df -B 1 | grep /newroot/var/lib | head -n 1 | awk -e '{print $3 }'", throwOnNonZero: true).Trim());
                        break;

                    case NandTasks.FlashUserPartition:
                        partitionSize = long.Parse(hakchi.Shell.ExecuteSimple($"blockdev --getsize64 {userDataDevice}", throwOnNonZero: true));
                        break;

                    case NandTasks.DumpNand:
                        partitionSize = 536870912;
                        break;
                    }

                    FileMode mode = FileMode.Create;

                    if (task == NandTasks.FlashUserPartition || task == NandTasks.FlashSystemPartition)
                    {
                        mode = FileMode.Open;
                    }

                    tasker.SetStatus(mode == FileMode.Open ? Resources.FlashingNand : Resources.DumpingNand);
                    using (var file = new TrackableFileStream(nandDump, mode, mode == FileMode.Open ? FileAccess.Read : FileAccess.ReadWrite))
                    {
                        if (mode == FileMode.Open && file.Length > partitionSize)
                        {
                            throw new Exception(Resources.ImageTooLarge);
                        }

                        if (mode == FileMode.Create && task != NandTasks.DumpUserPartition && task != NandTasks.DumpSystemPartition)
                        {
                            file.SetLength(partitionSize);
                        }

                        if (task == NandTasks.DumpUserPartition)
                        {
                            file.OnProgress += (long position, long length) =>
                            {
                                tasker.OnProgress(Math.Min(position, partitionSize), partitionSize);
                            };
                        }
                        else if (task == NandTasks.DumpSystemPartition && !systemIsHsqs)
                        {
                            file.OnProgress += (long position, long length) =>
                            {
                                tasker.OnProgress(Math.Min(position, partitionSize) + partitionSize, partitionSize * 2);
                            };
                        }
                        else
                        {
                            file.OnProgress += tasker.OnProgress;
                        }

                        switch (task)
                        {
                        case NandTasks.DumpSystemPartition:
                            if (systemIsHsqs)
                            {
                                Shared.ShellPipe($"dd if={osDecryptedDevice} bs=128K count={(partitionSize / 1024) / 4 }", null, file, throwOnNonZero: true);
                            }
                            else
                            {
                                Regex mksquashfsProgress = new Regex(@"(\d+)/(\d+)", RegexOptions.Compiled);
                                using (var mksquashfs = File.OpenRead(Path.Combine(Program.BaseDirectoryInternal, "tools", "mksquashfs")))
                                {
                                    hakchi.Shell.Execute("cat > /mksquashfs", mksquashfs, throwOnNonZero: true);
                                    hakchi.Shell.Execute("chmod +x /mksquashfs", throwOnNonZero: true);
                                }

                                hakchi.Shell.ExecuteSimple("hakchi mount_base");
                                hakchi.Shell.ExecuteSimple("mkdir -p /tmp/");
                                using (EventStream mkSquashfsProgress = new EventStream())
                                {
                                    splitStream.AddStreams(mkSquashfsProgress);
                                    mkSquashfsProgress.OnData += (byte[] buffer) =>
                                    {
                                        string data = Encoding.ASCII.GetString(buffer);
                                        MatchCollection matches = mksquashfsProgress.Matches(data);

                                        if (matches.Count > 0)
                                        {
                                            tasker.SetProgress(long.Parse(matches[matches.Count - 1].Groups[1].Value), long.Parse(matches[matches.Count - 1].Groups[2].Value) * 2);
                                        }
                                    };

                                    hakchi.Shell.Execute("/mksquashfs /newroot/var/squashfs /tmp/rootfs.hsqs", null, splitStream, splitStream, throwOnNonZero: true);

                                    splitStream.RemoveStream(mkSquashfsProgress);
                                }

                                partitionSize = long.Parse(hakchi.Shell.ExecuteSimple("ls -la /tmp/rootfs.hsqs | awk -e '{ print $5 }'"));

                                hakchi.Shell.ExecuteSimple("hakchi umount_base");
                                Shared.ShellPipe("cat /tmp/rootfs.hsqs", stdout: file);
                                hakchi.Shell.ExecuteSimple("rm /tmp/rootfs.hsqs");
                            }

                            break;

                        case NandTasks.FlashSystemPartition:
                            if (isTar || (hakchi.IsMdPartitioning && !isExtFs))
                            {
                                using (var eventStream = new EventStream())
                                {
                                    eventStream.OnData += (byte[] data) =>
                                    {
                                        var dataString = Encoding.UTF8.GetString(data).Trim();
                                        tasker.SetStatus(dataString);
                                        Trace.WriteLine(dataString);
                                    };

                                    hakchi.Shell.Execute("mkdir -p /tmp/rootfs /tmp/squashfs", throwOnNonZero: true);

                                    if (isHsqs)
                                    {
                                        Shared.ShellPipe($"dd of=/tmp/squashfs/squash.hsqs bs=128K", file, throwOnNonZero: true);
                                    }

                                    ShellTasks.FormatDevice(osDecryptedDevice)(tasker);
                                    hakchi.Shell.Execute($"mount {osDecryptedDevice} /tmp/rootfs", throwOnNonZero: true);

                                    if (isTar)
                                    {
                                        hakchi.Shell.Execute($"tar -xvf - -C /tmp/rootfs", file, eventStream, null, throwOnNonZero: true);
                                    }
                                    else if (isHsqs)
                                    {
                                        tasker.SetStatus(Resources.FlashingNand);
                                        hakchi.Shell.Execute($"mount /tmp/squashfs/squash.hsqs /tmp/squashfs/", throwOnNonZero: true);
                                        hakchi.Shell.Execute("cd /tmp/squashfs; rsync -av ./ ../rootfs", null, eventStream, eventStream, throwOnNonZero: true);
                                        hakchi.Shell.Execute("umount /tmp/squashfs", throwOnNonZero: true);
                                        hakchi.Shell.Execute("rm -rf /tmp/squashfs", throwOnNonZero: true);
                                    }

                                    hakchi.Shell.Execute("umount /tmp/rootfs", throwOnNonZero: true);
                                    hakchi.Shell.Execute("rmdir /tmp/rootfs", throwOnNonZero: true);
                                }
                            }
                            else
                            {
                                Shared.ShellPipe($"dd of={osDecryptedDevice} bs=128K", file, throwOnNonZero: true);
                            }

                            if (hasKeyfile)
                            {
                                hakchi.Shell.Execute("cryptsetup close root-crypt", throwOnNonZero: true);
                            }
                            break;

                        case NandTasks.DumpUserPartition:
                            Shared.ShellPipe($"tar -cvC /newroot/var/lib/ .", null, file, null, throwOnNonZero: true);
                            break;

                        case NandTasks.FlashUserPartition:
                            if (isTar)
                            {
                                hakchi.Shell.Execute("hakchi mount_base", null, null, null, 0, true);
                                hakchi.Shell.Execute("rm -rf /newroot/var/lib/*", null, null, null, 0, true);
                                hakchi.Shell.Execute("tar -xvC /newroot/var/lib/", file, throwOnNonZero: true);
                            }
                            else
                            {
                                Shared.ShellPipe($"dd of={userDataDevice} bs=128K", file, throwOnNonZero: true);
                            }
                            break;

                        case NandTasks.DumpNand:
                            hakchi.Shell.Execute("hakchi umount_base", null, splitStream, splitStream, 0, true);
                            Shared.ShellPipe("sntool sunxi_flash phy_read 0", null, file, throwOnNonZero: true);
                            break;
                        }
                        file.Close();
                    }

                    tasker.SetStatus(Resources.Done);
                    tasker.SetProgress(1, 1);
                    return Conclusion.Success;
                });
            });
        }
예제 #3
0
        public Tasker.Conclusion AddGames(Tasker tasker, Object syncObject = null)
        {
            tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.AddingGames);
            tasker.SetTitle(Resources.AddingGames);
            tasker.SetStatusImage(Resources.sign_cogs);

            // static presets
            NesApplication.ParentForm           = tasker.HostForm;
            NesApplication.NeedPatch            = null;
            NesApplication.Need3rdPartyEmulator = null;
            NesApplication.CachedCoverFiles     = null;
            NesGame.IgnoreMapper           = null;
            SnesGame.NeedAutoDownloadCover = null;

            int total = files.Count();
            int count = 0;
            var gamesWithMultipleArt = new List <NesApplication>();

            foreach (var sourceFileName in files)
            {
                NesApplication app = null;
                try
                {
                    tasker.SetStatus(string.Format(Resources.AddingGame, Path.GetFileName(sourceFileName)));
                    var    fileName = sourceFileName;
                    var    ext      = Path.GetExtension(sourceFileName).ToLower();
                    byte[] rawData  = null;
                    string tmp      = null;
                    if (!asIs && (ext == ".7z" || ext == ".zip" || ext == ".rar" || ext == ".clvg"))
                    {
                        if (ext == ".clvg")
                        {
                            tmp = TempHelpers.getUniqueTempPath();
                            Directory.CreateDirectory(tmp);

                            using (var file = File.OpenRead(sourceFileName))
                                using (var reader = ReaderFactory.Open(file))
                                {
                                    reader.WriteAllToDirectory(tmp, new ExtractionOptions()
                                    {
                                        ExtractFullPath = true, PreserveFileTime = true
                                    });
                                }

                            var gameFilesInArchive = Directory.GetFiles(tmp, "*.desktop").Select(o => new DirectoryInfo(o)).Cast <DirectoryInfo>().ToArray();

                            switch (gameFilesInArchive.LongLength)
                            {
                            case 0:
                                // no files found
                                break;

                            case 1:
                                // one file found
                                fileName = gameFilesInArchive[0].FullName;
                                break;

                            default:
                                // multiple files found
                                var r = SelectFile(tasker, gameFilesInArchive.Select(o => o.FullName).ToArray());
                                if (r == DialogResult.OK)
                                {
                                    fileName = selectedFile;
                                }
                                else if (r == DialogResult.Ignore)
                                {
                                    fileName = sourceFileName;
                                }
                                else
                                {
                                    continue;
                                }
                                break;
                            }
                        }
                        else
                        {
                            using (var extractor = ArchiveFactory.Open(sourceFileName))
                            {
                                var filesInArchive     = extractor.Entries;
                                var gameFilesInArchive = new List <string>();
                                foreach (var f in extractor.Entries)
                                {
                                    if (!f.IsDirectory)
                                    {
                                        var e = Path.GetExtension(f.Key).ToLower();
                                        if (e == ".desktop")
                                        {
                                            gameFilesInArchive.Clear();
                                            gameFilesInArchive.Add(f.Key);
                                            break;
                                        }
                                        else if (CoreCollection.Extensions.Contains(e))
                                        {
                                            gameFilesInArchive.Add(f.Key);
                                        }
                                    }
                                }
                                if (gameFilesInArchive.Count == 1) // Only one known file (or app)
                                {
                                    fileName = gameFilesInArchive[0];
                                }
                                else if (gameFilesInArchive.Count > 1) // Many known files, need to select
                                {
                                    var r = SelectFile(tasker, gameFilesInArchive.ToArray());
                                    if (r == DialogResult.OK)
                                    {
                                        fileName = selectedFile;
                                    }
                                    else if (r == DialogResult.Ignore)
                                    {
                                        fileName = sourceFileName;
                                    }
                                    else
                                    {
                                        continue;
                                    }
                                }
                                else if (filesInArchive.Count() == 1) // No known files but only one another file
                                {
                                    fileName = filesInArchive.First().Key;
                                }
                                else // Need to select
                                {
                                    var r = SelectFile(tasker, filesInArchive.Select(f => f.Key).ToArray());
                                    if (r == DialogResult.OK)
                                    {
                                        fileName = selectedFile;
                                    }
                                    else if (r == DialogResult.Ignore)
                                    {
                                        fileName = sourceFileName;
                                    }
                                    else
                                    {
                                        continue;
                                    }
                                }
                                if (fileName != sourceFileName)
                                {
                                    var o = new MemoryStream();
                                    if (Path.GetExtension(fileName).ToLower() == ".desktop" || // App in archive, need the whole directory
                                        filesInArchive.Select(f => f.Key).Contains(Path.GetFileNameWithoutExtension(fileName) + ".jpg") || // Or it has cover in archive
                                        filesInArchive.Select(f => f.Key).Contains(Path.GetFileNameWithoutExtension(fileName) + ".png") ||
                                        filesInArchive.Select(f => f.Key).Contains(Path.GetFileNameWithoutExtension(fileName) + ".ips")    // Or IPS file
                                        )
                                    {
                                        tmp = Path.Combine(tempDirectory, fileName);
                                        Directory.CreateDirectory(tmp);
                                        extractor.WriteToDirectory(tmp, new ExtractionOptions()
                                        {
                                            ExtractFullPath = true, Overwrite = true
                                        });
                                        fileName = Path.Combine(tmp, fileName);
                                    }
                                    else
                                    {
                                        extractor.Entries.Where(f => f.Key == fileName).First().WriteTo(o);
                                        rawData = new byte[o.Length];
                                        o.Seek(0, SeekOrigin.Begin);
                                        o.Read(rawData, 0, (int)o.Length);
                                    }
                                }
                            }
                        }
                    }
                    app = NesApplication.Import(fileName, sourceFileName, rawData, asIs);

                    if (ext == ".clvg")
                    {
                        app.SkipCoreSelect = true;
                    }
                    else
                    {
                        if (app != null && app.CoverArtMatches != null && app.CoverArtMatches.Count() > 1)
                        {
                            gamesWithMultipleArt.Add(app);
                        }
                        NewGames.Add(app);
                    }

                    if (app is ISupportsGameGenie && Path.GetExtension(fileName).ToLower() == ".nes")
                    {
                        var lGameGeniePath = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName) + ".xml");
                        if (File.Exists(lGameGeniePath))
                        {
                            GameGenieDataBase lGameGenieDataBase = new GameGenieDataBase(app);
                            lGameGenieDataBase.ImportCodes(lGameGeniePath, true);
                            lGameGenieDataBase.Save();
                        }
                    }

                    if (!string.IsNullOrEmpty(tmp) && Directory.Exists(tmp))
                    {
                        Directory.Delete(tmp, true);
                    }
                }
                catch (Exception ex)
                {
                    if (ex is ThreadAbortException)
                    {
                        return(Tasker.Conclusion.Abort);
                    }
                    if (ex.InnerException != null && !string.IsNullOrEmpty(ex.InnerException.Message))
                    {
                        Trace.WriteLine(ex.InnerException.Message + ex.InnerException.StackTrace);
                        tasker.ShowError(ex.InnerException, Path.GetFileName(sourceFileName));
                    }
                    else
                    {
                        Trace.WriteLine(ex.Message + ex.StackTrace, Path.GetFileName(sourceFileName));
                        tasker.ShowError(ex);
                    }
                    return(Tasker.Conclusion.Error);
                }
                if (app != null)
                {
                    addedApps.Add(app);
                }
                tasker.SetProgress(++count, total);
            }
            if (gamesWithMultipleArt.Count > 0)
            {
                tasker.HostForm.Invoke(new Action(() => {
                    using (SelectCoverDialog selectCoverDialog = new SelectCoverDialog())
                    {
                        selectCoverDialog.Games.AddRange(gamesWithMultipleArt);
                        selectCoverDialog.ShowDialog(tasker.HostForm);
                    }
                }));
            }
            return(Tasker.Conclusion.Success);
        }
예제 #4
0
        /// <summary>
        /// Rewrites arguments of an invocation according to the receiving method. It is assumed
        /// that arguments match parameters, but may need to be expanded/reordered.
        /// </summary>
        private void RewriteArguments(
            MethodSymbol method,
            bool expanded,
            ReadOnlyArray <int> argsToParamsOpt,
            ref ReadOnlyArray <RefKind> argumentRefKinds,
            ref ReadOnlyArray <BoundExpression> rewrittenArguments,
            out ReadOnlyArray <LocalSymbol> temporaries)
        {
            // We have:
            // * a list of arguments, already converted to their proper types,
            //   in source code order. Some optional arguments might be missing.
            // * a map showing which parameter each argument corresponds to. If
            //   this is null, then the argument to parameter mapping is one-to-one.
            // * the ref kind of each argument, in source code order. That is, whether
            //   the argument was marked as ref, out, or value (neither).
            // * a method symbol.
            // * whether the call is expanded or normal form.

            // We rewrite the call so that:
            // * if in its expanded form, we create the params array.
            // * if the call requires reordering of arguments because of named arguments, temporaries are generated as needed

            // Doing this transformation can move around refness in interesting ways. For example, consider
            //
            // A().M(y : ref B()[C()], x : out D());
            //
            // This will be created as a call with receiver A(), symbol M, argument list ( B()[C()], D() ),
            // name list ( y, x ) and ref list ( ref, out ).  We can rewrite this into temporaries:
            //
            // A().M(
            //    seq ( ref int temp_y = ref B()[C()], out D() ),
            //    temp_y );
            //
            // Now we have a call with receiver A(), symbol M, argument list as shown, no name list,
            // and ref list ( out, value ). We do not want to pass a *ref* to temp_y; the temporary
            // storage is not the thing being ref'd! We want to pass the *value* of temp_y, which
            // *contains* a reference.

            // We attempt to minimize the number of temporaries required. Arguments which neither
            // produce nor observe a side effect can be placed into their proper position without
            // recourse to a temporary. For example:
            //
            // Where(predicate: x=>x.Length!=0, sequence: S())
            //
            // can be rewritten without any temporaries because the conversion from lambda to
            // delegate does not produce any side effect that could be observed by S().
            //
            // By contrast:
            //
            // Foo(z: this.p, y: this.Q(), x: (object)10)
            //
            // The boxing of 10 can be reordered, but the fetch of this.p has to happen before the
            // call to this.Q() because the call could change the value of this.p.
            //
            // We start by binding everything that is not obviously reorderable as a temporary, and
            // then run an optimizer to remove unnecessary temporaries.

            ReadOnlyArray <ParameterSymbol> parameters = method.Parameters;
            var parameterCount = parameters.Count;
            var arguments      = new BoundExpression[parameterCount];

            temporaries = ReadOnlyArray <LocalSymbol> .Null;  // not using temps by default.

            List <RefKind> refKinds = null;

            if (argumentRefKinds.IsNotNull)
            {
                refKinds = new List <RefKind>(parameterCount);
                for (int p = 0; p < parameterCount; ++p)
                {
                    refKinds.Add(RefKind.None);
                }
            }

            ArrayBuilder <BoundAssignmentOperator> storesToTemps = null;
            ArrayBuilder <BoundExpression>         paramArray    = null;

            if (expanded)
            {
                paramArray = ArrayBuilder <BoundExpression> .GetInstance();
            }

            for (int a = 0; a < rewrittenArguments.Count; ++a)
            {
                var argument = rewrittenArguments[a];
                var p        = (argsToParamsOpt.IsNotNull) ? argsToParamsOpt[a] : a;
                var refKind  = argumentRefKinds.RefKinds(a);
                Debug.Assert(arguments[p] == null);
                if (expanded && p == parameterCount - 1)
                {
                    paramArray.Add(argument);
                    Debug.Assert(refKind == RefKind.None);
                }
                else if (IsSafeForReordering(argument, refKind))
                {
                    arguments[p] = argument;
                    if (refKinds != null)
                    {
                        refKinds[p] = refKind;
                    }
                }
                else
                {
                    if (storesToTemps == null)
                    {
                        storesToTemps = ArrayBuilder <BoundAssignmentOperator> .GetInstance(rewrittenArguments.Count);
                    }

                    var tempStore = TempHelpers.StoreToTemp(argument, refKind, containingSymbol);
                    storesToTemps.Add(tempStore.Item1);
                    arguments[p] = tempStore.Item2;
                }
            }

            if (expanded)
            {
                var paramArrayType = parameters[parameterCount - 1].Type;
                var arrayArgs      = paramArray.ToReadOnlyAndFree();

                var int32Type = method.ContainingAssembly.GetPrimitiveType(Microsoft.Cci.PrimitiveTypeCode.Int32);

                arguments[parameterCount - 1] = new BoundArrayCreation(
                    null,
                    null,
                    ReadOnlyArray.Singleton <BoundExpression>(
                        new BoundLiteral(null, null, ConstantValue.Create(arrayArgs.Count), int32Type)),
                    new BoundArrayInitialization(null, null, arrayArgs),
                    paramArrayType);
            }

            for (int p = 0; p < parameterCount; ++p)
            {
                if (arguments[p] == null)
                {
                    Debug.Assert(parameters[p].IsOptional);

                    // UNDONE: Add optional arguments.
                }
            }

            if (storesToTemps != null)
            {
                int tempsNeeded = MergeArgumentsAndSideEffects(storesToTemps, arguments);

                if (tempsNeeded > 0)
                {
                    var temps = new LocalSymbol[tempsNeeded];
                    for (int i = 0, j = 0; i < storesToTemps.Count; i++)
                    {
                        var s = storesToTemps[i];
                        if (s != null)
                        {
                            temps[j++] = ((BoundLocal)s.Left).LocalSymbol;
                        }
                    }

                    temporaries = temps.AsReadOnlyWrap();
                }

                storesToTemps.Free();
            }

            // * The rewritten list of names is now null because the arguments have been reordered.
            // * The args-to-params map is now null because every argument exactly matches its parameter.
            // * The call is no longer in its expanded form.

            argumentRefKinds   = refKinds == null ? ReadOnlyArray <RefKind> .Null : refKinds.AsReadOnly <RefKind>();
            rewrittenArguments = arguments.AsReadOnlyWrap();
        }
예제 #5
0
        public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node)
        {
            if (node.HasErrors)
            {
                return(node);
            }

            // There are five possible cases.
            //
            // Case 1: receiver.Prop += value is transformed into
            // temp = receiver
            // temp.Prop = temp.Prop + value
            // and a later rewriting will turn that into calls to getters and setters.
            //
            // Case 2: collection[i1, i2, i3] += value is transformed into
            // tc = collection
            // t1 = i1
            // t2 = i2
            // t3 = i3
            // tc[t1, t2, t3] = tc[t1, t2, t3] + value
            // and again, a later rewriting will turn that into getters and setters of the indexer.
            //
            // Case 3: local += value (and param += value) needs no temporaries; it simply
            // becomes local = local + value.
            //
            // Case 4: staticField += value needs no temporaries either. However, classInst.field += value becomes
            // temp = classInst
            // temp.field = temp.field + value
            //
            // Case 5: otherwise, it must be structVariable.field += value or array[index] += value. Either way
            // we have a variable on the left. Transform it into:
            // ref temp = ref variable
            // temp = temp + value

            var temps = ArrayBuilder <LocalSymbol> .GetInstance();

            var stores = ArrayBuilder <BoundExpression> .GetInstance();

            // This will be filled in with the LHS that uses temporaries to prevent
            // double-evaluation of side effects.

            BoundExpression transformedLHS = null;

            if (node.Left.Kind == BoundKind.PropertyAccess)
            {
                // We need to stash away the receiver so that it does not get evaluated twice.
                // If the receiver is classified as a value of reference type then we can simply say
                //
                // R temp = receiver
                // temp.prop = temp.prop + rhs
                //
                // But if the receiver is classified as a variable of struct type then we
                // cannot make a copy of the value; we need to make sure that we mutate
                // the original receiver, not the copy.  We have to generate
                //
                // ref R temp = ref receiver
                // temp.prop = temp.prop + rhs
                //
                // The rules of C# (in section 7.17.1) require that if you have receiver.prop
                // as the target of an assignment such that receiver is a value type, it must
                // be classified as a variable. If we've gotten this far in the rewriting,
                // assume that was the case.

                var prop = (BoundPropertyAccess)node.Left;

                // If the property is static then we can just generate prop = prop + value
                if (prop.ReceiverOpt == null)
                {
                    transformedLHS = prop;
                }
                else
                {
                    // Can we ever avoid storing the receiver in a temp? If the receiver is a variable then it
                    // might be modified by the computation of the getter, the value, or the operation.
                    // The receiver cannot be a null constant or constant of value type. It could be a
                    // constant of string type, but there are no mutable properties of a string.
                    // Similarly, there are no mutable properties of a Type object, so the receiver
                    // cannot be a typeof(T) expression. The only situation I can think of where we could
                    // optimize away the temp is if the receiver is a readonly field of reference type,
                    // we are not in a constructor, and the receiver of the *field*, if any, is also idempotent.
                    // It doesn't seem worthwhile to pursue an optimization for this exceedingly rare case.

                    var rewrittenReceiver = (BoundExpression)Visit(prop.ReceiverOpt);
                    var receiverTemp      = TempHelpers.StoreToTemp(rewrittenReceiver, rewrittenReceiver.Type.IsValueType ? RefKind.Ref : RefKind.None, containingSymbol);
                    stores.Add(receiverTemp.Item1);
                    temps.Add(receiverTemp.Item2.LocalSymbol);
                    transformedLHS = new BoundPropertyAccess(prop.Syntax, prop.SyntaxTree, receiverTemp.Item2, prop.PropertySymbol, prop.Type);
                }
            }
            else if (node.Left.Kind == BoundKind.IndexerAccess)
            {
                var             indexer             = (BoundIndexerAccess)node.Left;
                BoundExpression transformedReceiver = null;
                if (indexer.ReceiverOpt != null)
                {
                    var rewrittenReceiver = (BoundExpression)Visit(indexer.ReceiverOpt);
                    var receiverTemp      = TempHelpers.StoreToTemp(rewrittenReceiver, rewrittenReceiver.Type.IsValueType ? RefKind.Ref : RefKind.None, containingSymbol);
                    transformedReceiver = receiverTemp.Item2;
                    stores.Add(receiverTemp.Item1);
                    temps.Add(receiverTemp.Item2.LocalSymbol);
                }

                // UNDONE: Dealing with the arguments is a bit tricky because they can be named out-of-order arguments;
                // UNDONE: we have to preserve both the source-code order of the side effects and the side effects
                // UNDONE: only being executed once.
                // UNDONE:
                // UNDONE: This is a subtly different problem than the problem faced by the conventional call
                // UNDONE: rewriter; with the conventional call rewriter we already know that the side effects
                // UNDONE: will only be executed once because the arguments are only being pushed on the stack once.
                // UNDONE: In a compound equality operator on an indexer the indices are placed on the stack twice.
                // UNDONE: That is to say, if you have:
                // UNDONE:
                // UNDONE: C().M(z : Z(), x : X(), y : Y())
                // UNDONE:
                // UNDONE: then we can rewrite that into
                // UNDONE:
                // UNDONE: tempc = C()
                // UNDONE: tempz = Z()
                // UNDONE: tempc.M(X(), Y(), tempz)
                // UNDONE:
                // UNDONE: See, we can optimize away two of the temporaries, for x and y. But we cannot optimize away any of the
                // UNDONE: temporaries in
                // UNDONE:
                // UNDONE: C().Collection[z : Z(), x : X(), y : Y()] += 1;
                // UNDONE:
                // UNDONE: because we have to ensure not just that Z() happens first, but in additioan that X() and Y() are only
                // UNDONE: called once.  We have to generate this as
                // UNDONE:
                // UNDONE: tempc = C().Collection
                // UNDONE: tempz = Z()
                // UNDONE: tempx = X()
                // UNDONE: tempy = Y()
                // UNDONE: tempc[tempx, tempy, tempz] = tempc[tempx, tempy, tempz] + 1;
                // UNDONE:
                // UNDONE: Fortunately arguments to indexers are never ref or out, so we don't need to worry about that.
                // UNDONE: However, we can still do the optimization where constants are not stored in
                // UNDONE: temporaries; if we have
                // UNDONE:
                // UNDONE: C().Collection[z : 123, y : Y(), x : X()] += 1;
                // UNDONE:
                // UNDONE: Then we can generate that as
                // UNDONE:
                // UNDONE: tempc = C().Collection
                // UNDONE: tempx = X()
                // UNDONE: tempy = Y()
                // UNDONE: tempc[tempx, tempy, 123] = tempc[tempx, tempy, 123] + 1;
                // UNDONE:
                // UNDONE: For now, we'll punt on both problems, as indexers are not implemented yet anyway.
                // UNDONE: We'll just generate one temporary for each argument. This will work, but in the
                // UNDONE: subsequent rewritings will generate more unnecessary temporaries.

                var transformedArguments = ArrayBuilder <BoundExpression> .GetInstance();

                foreach (var argument in indexer.Arguments)
                {
                    var rewrittenArgument = (BoundExpression)Visit(argument);
                    var argumentTemp      = TempHelpers.StoreToTemp(rewrittenArgument, RefKind.None, containingSymbol);
                    transformedArguments.Add(argumentTemp.Item2);
                    stores.Add(argumentTemp.Item1);
                    temps.Add(argumentTemp.Item2.LocalSymbol);
                }

                transformedLHS = new BoundIndexerAccess(indexer.Syntax, indexer.SyntaxTree, transformedArguments.ToReadOnlyAndFree(), transformedReceiver,
                                                        indexer.IndexerSymbol, indexer.Type);
            }
            else if (node.Left.Kind == BoundKind.Local || node.Left.Kind == BoundKind.Parameter)
            {
                // No temporaries are needed. Just generate local = local + value
                transformedLHS = node.Left;
            }
            else if (node.Left.Kind == BoundKind.FieldAccess)
            {
                // * If the field is static then no temporaries are needed.
                // * If the field is not static and the receiver is of reference type then generate t = r; t.f = t.f + value
                // * If the field is not static and the receiver is a variable of value type then we'll fall into the
                //   general variable case below.

                var fieldAccess = (BoundFieldAccess)node.Left;
                if (fieldAccess.ReceiverOpt == null)
                {
                    transformedLHS = fieldAccess;
                }
                else if (!fieldAccess.ReceiverOpt.Type.IsValueType)
                {
                    var rewrittenReceiver = (BoundExpression)Visit(fieldAccess.ReceiverOpt);
                    var receiverTemp      = TempHelpers.StoreToTemp(rewrittenReceiver, RefKind.None, containingSymbol);
                    stores.Add(receiverTemp.Item1);
                    temps.Add(receiverTemp.Item2.LocalSymbol);
                    transformedLHS = new BoundFieldAccess(fieldAccess.Syntax, fieldAccess.SyntaxTree, receiverTemp.Item2, fieldAccess.FieldSymbol, null);
                }
            }

            if (transformedLHS == null)
            {
                // We made no transformation above. Either we have array[index] += value or
                // structVariable.field += value; either way we have a potentially complicated variable-
                // producing expression on the left. Generate
                // ref temp = ref variable; temp = temp + value
                var rewrittenVariable = (BoundExpression)Visit(node.Left);
                var variableTemp      = TempHelpers.StoreToTemp(rewrittenVariable, RefKind.Ref, containingSymbol);
                stores.Add(variableTemp.Item1);
                temps.Add(variableTemp.Item2.LocalSymbol);
                transformedLHS = variableTemp.Item2;
            }

            // OK, we now have the temporary declarations, the temporary stores, and the transformed left hand side.
            // We need to generate
            //
            // xlhs = (FINAL)((LEFT)xlhs op rhs)
            //
            // And then wrap it up with the generated temporaries.
            //
            // (The right hand side has already been converted to the type expected by the operator.)

            BoundExpression opLHS = BoundConversion.SynthesizedConversion(transformedLHS, node.LeftConversion, node.Operator.LeftType);

            Debug.Assert(node.Right.Type == node.Operator.RightType);
            BoundExpression op         = new BoundBinaryOperator(null, null, node.Operator.Kind, opLHS, node.Right, null, node.Operator.ReturnType);
            BoundExpression opFinal    = BoundConversion.SynthesizedConversion(op, node.FinalConversion, node.Left.Type);
            BoundExpression assignment = new BoundAssignmentOperator(null, null, transformedLHS, opFinal, node.Left.Type);

            // OK, at this point we have:
            //
            // * temps evaluating and storing portions of the LHS that must be evaluated only once.
            // * the "transformed" left hand side, rebuilt to use temps where necessary
            // * the assignment "xlhs = (FINAL)((LEFT)xlhs op (RIGHT)rhs)"
            //
            // Notice that we have recursively rewritten the bound nodes that are things stored in
            // the temps, but we might have more rewriting to do on the assignment. There are three
            // conversions in there that might be lowered to method calls, an operator that might
            // be lowered to delegate combine, string concat, and so on, and don't forget, we
            // haven't lowered the right hand side at all! Let's rewrite all these things at once.

            BoundExpression rewrittenAssignment = (BoundExpression)Visit(assignment);

            BoundExpression result = (temps.Count == 0) ?
                                     rewrittenAssignment :
                                     new BoundSequence(null,
                                                       null,
                                                       temps.ToReadOnly(),
                                                       stores.ToReadOnly(),
                                                       rewrittenAssignment,
                                                       rewrittenAssignment.Type);

            temps.Free();
            stores.Free();
            return(result);
        }
예제 #6
0
        private void AddMods(string[] files, bool moveHmod = false)
        {
            foreach (var file in files)
            {
                var ext = Path.GetExtension(file).ToLower();
                if (ext == ".hmod")
                {
                    var target = Path.Combine(usermodsDirectory, $"{Hmod.GetCleanName(Path.GetFileNameWithoutExtension(file), true)}.hmod");

                    if (File.Exists(target))
                    {
                        File.Delete(target);
                    }

                    if (Directory.Exists(target))
                    {
                        Directory.Delete(target, true);
                    }

                    if (file != target)
                    {
                        if (Directory.Exists(file))
                        {
                            if (moveHmod)
                            {
                                Directory.Move(file, target);
                            }
                            else
                            {
                                Shared.DirectoryCopy(file, target, true, false, true, false);
                            }
                        }
                        else
                        {
                            if (moveHmod)
                            {
                                File.Move(file, target);
                            }
                            else
                            {
                                File.Copy(file, target, true);
                            }
                        }
                    }

                    var rawName = Path.GetFileNameWithoutExtension(target);

                    hmods.RemoveAll(m => m.RawName == rawName);
                    hmods.Add(new Hmod(rawName));
                }
                else if (ext == ".7z" || ext == ".zip" || ext == ".rar" || ext == ".tar")
                {
                    var newHmods = new List <string>();
                    using (var extractor = ArchiveFactory.Open(file))
                    {
                        TempHelpers.doWithTempFolder(temp =>
                        {
                            extractor.WriteToDirectory(temp, new ExtractionOptions()
                            {
                                ExtractFullPath = true
                            });
                            AddMods(Directory.EnumerateDirectories(temp, "*.hmod", SearchOption.AllDirectories).ToArray(), true);
                            AddMods(Directory.EnumerateFiles(temp, "*.hmod", SearchOption.AllDirectories).ToArray(), true);
                        }, true, usermodsDirectory);
                    }
                }
            }

            populateList();
        }
예제 #7
0
        public Tasker.Conclusion AddGames(Tasker tasker, Object syncObject = null)
        {
            tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.AddingGames);
            tasker.SetTitle(Resources.AddingGames);
            tasker.SetStatusImage(Resources.sign_cogs);

            // static presets
            NesApplication.ParentForm           = tasker.HostForm;
            NesApplication.NeedPatch            = null;
            NesApplication.Need3rdPartyEmulator = null;
            NesApplication.CachedCoverFiles     = null;
            NesGame.IgnoreMapper           = null;
            SnesGame.NeedAutoDownloadCover = null;

            int total = files.Count();
            int count = 0;
            var gamesWithMultipleArt = new List <NesApplication>();

            foreach (var sourceFileName in files)
            {
                NesApplication app = null;
                try
                {
                    tasker.SetStatus(string.Format(Resources.AddingGame, Path.GetFileName(sourceFileName)));
                    var    fileName = sourceFileName;
                    var    ext      = Path.GetExtension(sourceFileName).ToLower();
                    byte[] rawData  = null;
                    string tmp      = null;
                    if (!asIs && (ext == ".7z" || ext == ".zip" || ext == ".rar" || ext == ".clvg"))
                    {
                        if (ext == ".clvg")
                        {
                            tmp = TempHelpers.getUniqueTempPath();
                            Directory.CreateDirectory(tmp);

                            using (var file = File.OpenRead(sourceFileName))
                                using (var reader = ReaderFactory.Open(file))
                                {
                                    reader.WriteAllToDirectory(tmp, new ExtractionOptions()
                                    {
                                        ExtractFullPath = true, PreserveFileTime = true
                                    });
                                }

                            var gameFilesInArchive = Directory.GetFiles(tmp, "*.desktop").Select(o => new DirectoryInfo(o)).Cast <DirectoryInfo>().ToArray();

                            switch (gameFilesInArchive.LongLength)
                            {
                            case 0:
                                // no files found
                                break;

                            case 1:
                                // one file found
                                fileName = gameFilesInArchive[0].FullName;
                                break;

                            default:
                                // multiple files found
                                var r = SelectFile(tasker, gameFilesInArchive.Select(o => o.FullName).ToArray());
                                if (r == DialogResult.OK)
                                {
                                    fileName = selectedFile;
                                }
                                else if (r == DialogResult.Ignore)
                                {
                                    fileName = sourceFileName;
                                }
                                else
                                {
                                    continue;
                                }
                                break;
                            }
                        }
                        else
                        {
                            using (var extractor = ArchiveFactory.Open(sourceFileName))
                            {
                                var filesInArchive     = extractor.Entries;
                                var gameFilesInArchive = new List <string>();
                                foreach (var f in extractor.Entries)
                                {
                                    if (!f.IsDirectory)
                                    {
                                        var e = Path.GetExtension(f.Key).ToLower();
                                        if (e == ".desktop")
                                        {
                                            gameFilesInArchive.Clear();
                                            gameFilesInArchive.Add(f.Key);
                                            break;
                                        }
                                        else if (CoreCollection.Extensions.Contains(e))
                                        {
                                            gameFilesInArchive.Add(f.Key);
                                        }
                                    }
                                }
                                if (gameFilesInArchive.Count == 1) // Only one known file (or app)
                                {
                                    fileName = gameFilesInArchive[0];
                                }
                                else if (gameFilesInArchive.Count > 1) // Many known files, need to select
                                {
                                    var r = SelectFile(tasker, gameFilesInArchive.ToArray());
                                    if (r == DialogResult.OK)
                                    {
                                        fileName = selectedFile;
                                    }
                                    else if (r == DialogResult.Ignore)
                                    {
                                        fileName = sourceFileName;
                                    }
                                    else
                                    {
                                        continue;
                                    }
                                }
                                else if (filesInArchive.Count() == 1) // No known files but only one another file
                                {
                                    fileName = filesInArchive.First().Key;
                                }
                                else // Need to select
                                {
                                    var r = SelectFile(tasker, filesInArchive.Select(f => f.Key).ToArray());
                                    if (r == DialogResult.OK)
                                    {
                                        fileName = selectedFile;
                                    }
                                    else if (r == DialogResult.Ignore)
                                    {
                                        fileName = sourceFileName;
                                    }
                                    else
                                    {
                                        continue;
                                    }
                                }
                                if (fileName != sourceFileName)
                                {
                                    var o = new MemoryStream();
                                    if (Path.GetExtension(fileName).ToLower() == ".desktop" || // App in archive, need the whole directory
                                        filesInArchive.Select(f => f.Key).Contains(Path.GetFileNameWithoutExtension(fileName) + ".jpg") || // Or it has cover in archive
                                        filesInArchive.Select(f => f.Key).Contains(Path.GetFileNameWithoutExtension(fileName) + ".png") ||
                                        filesInArchive.Select(f => f.Key).Contains(Path.GetFileNameWithoutExtension(fileName) + ".ips")    // Or IPS file
                                        )
                                    {
                                        tmp = Path.Combine(tempDirectory, fileName);
                                        Directory.CreateDirectory(tmp);
                                        extractor.WriteToDirectory(tmp, new ExtractionOptions()
                                        {
                                            ExtractFullPath = true, Overwrite = true
                                        });
                                        fileName = Path.Combine(tmp, fileName);
                                    }
                                    else
                                    {
                                        extractor.Entries.Where(f => f.Key == fileName).First().WriteTo(o);
                                        rawData = new byte[o.Length];
                                        o.Seek(0, SeekOrigin.Begin);
                                        o.Read(rawData, 0, (int)o.Length);
                                    }
                                }
                            }
                        }
                    }
                    app = NesApplication.Import(fileName, sourceFileName, rawData, asIs);

                    if (ext == ".clvg")
                    {
                        app.SkipCoreSelect = true;
                    }
                    else
                    {
                        if (app.CoverArtMatches != null && app.CoverArtMatches.Count() > 1)
                        {
                            gamesWithMultipleArt.Add(app);
                        }
                        if (ConfigIni.Instance.EnableImportScraper && Program.TheGamesDBAPI != null &&
                            app.Metadata.OriginalCrc32 != 0 &&
                            data.GamesDB.HashLookup.ContainsKey(app.Metadata.OriginalCrc32) &&
                            data.GamesDB.HashLookup[app.Metadata.OriginalCrc32].Length > 0)
                        {
                            var api  = Program.TheGamesDBAPI;
                            var task = api.GetInfoByID(data.GamesDB.HashLookup[app.Metadata.OriginalCrc32]);
                            try
                            {
                                task.Wait();
                                var result = task.Result;

                                if (result.Items.Count() > 0)
                                {
                                    var first = result.Items.First();

                                    if (first.Name != null)
                                    {
                                        app.Desktop.Name     = first.Name;
                                        app.Desktop.SortName = Shared.GetSortName(first.Name);
                                    }

                                    if (first.Publishers != null && first.Publishers.Length > 0)
                                    {
                                        app.Desktop.Publisher = String.Join(", ", first.Publishers).ToUpper();
                                    }
                                    else if (first.Developers != null && first.Developers.Length > 0)
                                    {
                                        if (first.ReleaseDate != null)
                                        {
                                            app.Desktop.Copyright = $"© {first.ReleaseDate.Year} {String.Join(", ", first.Developers)}";
                                        }
                                        else
                                        {
                                            app.Desktop.Copyright = $"© {String.Join(", ", first.Developers)}";
                                        }
                                    }

                                    if (first.Description != null)
                                    {
                                        app.Desktop.Description = first.Description;
                                    }

                                    if (first.ReleaseDate != null)
                                    {
                                        app.Desktop.ReleaseDate = first.ReleaseDate.ToString("yyyy-MM-dd");
                                    }

                                    if (first.PlayerCount > 0)
                                    {
                                        app.Desktop.Players      = Convert.ToByte(first.PlayerCount);
                                        app.Desktop.Simultaneous = first.PlayerCount == 2;
                                    }

                                    if (first.Genres != null && first.Genres.Length > 0)
                                    {
                                        foreach (var genre in first.Genres)
                                        {
                                            var match = ScraperForm.TheGamesDBGenreLookup.Where(g => g.Value.Contains(genre.ID)).Select(g => g.Key);

                                            if (match.Count() > 0)
                                            {
                                                var firstGenre = match.First();

                                                app.Desktop.Genre = firstGenre;
                                                break;
                                            }
                                        }
                                    }

                                    using (var wc = new HakchiWebClient())
                                    {
                                        try
                                        {
                                            var front = first.Images.Where(i => i.Type == TeamShinkansen.Scrapers.Enums.ArtType.Front).ToArray();

                                            if (front.Length > 0 && !app.CoverArtMatchSuccess)
                                            {
                                                var data = wc.DownloadData(front[0].Url);
                                                using (var ms = new MemoryStream(data))
                                                    using (var bm = new Bitmap(ms))
                                                    {
                                                        app.SetImage(bm);
                                                    }
                                            }
                                        }
                                        catch (WebException ex) { }

                                        try
                                        {
                                            var imageData = wc.DownloadData($"https://cdn.thegamesdb.net/images/original/clearlogo/{first.ID}.png");

                                            using (var ms = new MemoryStream(imageData))
                                                using (var clearLogo = File.OpenWrite(Path.Combine(app.BasePath, $"{app.Code}_logo.png")))
                                                {
                                                    ms.Seek(0, SeekOrigin.Begin);
                                                    ms.CopyTo(clearLogo);
                                                }
                                        }
                                        catch (WebException ex) { }
                                    }
                                }
                            }
                            catch (Exception) { }
                        }
                    }

                    if (app is ISupportsGameGenie && Path.GetExtension(fileName).ToLower() == ".nes")
                    {
                        var lGameGeniePath = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName) + ".xml");
                        if (File.Exists(lGameGeniePath))
                        {
                            GameGenieDataBase lGameGenieDataBase = new GameGenieDataBase(app);
                            lGameGenieDataBase.ImportCodes(lGameGeniePath, true);
                            lGameGenieDataBase.Save();
                        }
                    }

                    if (!string.IsNullOrEmpty(tmp) && Directory.Exists(tmp))
                    {
                        Directory.Delete(tmp, true);
                    }
                }
                catch (Exception ex)
                {
                    if (ex is ThreadAbortException)
                    {
                        return(Tasker.Conclusion.Abort);
                    }
                    if (ex.InnerException != null && !string.IsNullOrEmpty(ex.InnerException.Message))
                    {
                        Trace.WriteLine(ex.InnerException.Message + ex.InnerException.StackTrace);
                        tasker.ShowError(ex.InnerException, Path.GetFileName(sourceFileName));
                    }
                    else
                    {
                        Trace.WriteLine(ex.Message + ex.StackTrace, Path.GetFileName(sourceFileName));
                        tasker.ShowError(ex);
                    }
                    return(Tasker.Conclusion.Error);
                }
                if (app != null)
                {
                    addedApps.Add(app);
                }
                tasker.SetProgress(++count, total);
            }
            if (gamesWithMultipleArt.Count > 0)
            {
                tasker.HostForm.Invoke(new Action(() => {
                    using (SelectCoverDialog selectCoverDialog = new SelectCoverDialog())
                    {
                        selectCoverDialog.Games.AddRange(gamesWithMultipleArt);
                        selectCoverDialog.ShowDialog(tasker.HostForm);
                    }
                }));
            }
            return(Tasker.Conclusion.Success);
        }