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