initial commit

This commit is contained in:
what 2021-07-26 13:04:16 -07:00
commit 1b60743303
274 changed files with 25866 additions and 0 deletions

View file

@ -0,0 +1,55 @@
// Decompiled with JetBrains decompiler
// Type: SEGATools.GDEmu.DiscTrackCopyInfo
// Assembly: SEGATools, Version=1.0.3.0, Culture=neutral, PublicKeyToken=611be24fdeb07e08
// MVID: D631183F-57B1-40A1-B502-5364D288307A
// Assembly location: SEGATools.dll
using ImageReader.DiscSectors;
using SEGATools.Binary;
using SEGATools.DiscFileSystem;
using System.Collections.Generic;
using System.Linq;
namespace SEGATools.GDEmu
{
internal class DiscTrackCopyInfo
{
private HashSet<BinaryPatch> patchesApplied;
public IDiscTrack SourceTrack { get; private set; }
public IDiscTrack DestinationTrack { get; private set; }
public int[] ModifiedSectors
{
get
{
HashSet<int> source = new HashSet<int>();
foreach (BinaryPatch binaryPatch in this.patchesApplied)
{
int num1 = (int) binaryPatch.Offset / DiscSectorCommon.LogicalSectorSize;
int num2 = (int) (binaryPatch.Offset + (long) binaryPatch.Data.Length) / DiscSectorCommon.LogicalSectorSize;
for (int index = num1; index <= num2; ++index)
source.Add(index);
}
return source.ToArray<int>();
}
}
public static DiscTrackCopyInfo CreateFrom(
IDiscTrack source,
string newFileName)
{
return new DiscTrackCopyInfo(source, DiscTrack.CreateCopyFrom(source, newFileName));
}
private DiscTrackCopyInfo(IDiscTrack source, IDiscTrack destination)
{
this.SourceTrack = source;
this.DestinationTrack = destination;
this.patchesApplied = new HashSet<BinaryPatch>();
}
public void AddPatches(params BinaryPatch[] patches) => this.patchesApplied.UnionWith((IEnumerable<BinaryPatch>) patches);
}
}

View file

@ -0,0 +1,328 @@
// Decompiled with JetBrains decompiler
// Type: SEGATools.GDEmu.GDEmuConverter
// Assembly: SEGATools, Version=1.0.3.0, Culture=neutral, PublicKeyToken=611be24fdeb07e08
// MVID: D631183F-57B1-40A1-B502-5364D288307A
// Assembly location: SEGATools.dll
using ImageReader.DiscSectors;
using ImageReader.Stream;
using SEGATools.Binary;
using SEGATools.Disc;
using SEGATools.DiscFileSystem;
using SEGATools.UserProcess;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
namespace SEGATools.GDEmu
{
public class GDEmuConverter : UserProcessBase
{
private static readonly int OutputFileStreamBuffer = 524288;
private static readonly string FileConflictQuestionTitle = "GDEmuExporterFileConflictQuestionTitle";
private static readonly string FileConflictQuestionContent = "GDEmuExporterFileConflictQuestionContent";
private static readonly string BinaryPatcherHint = "GDEmuExporterBinaryPatcherHint";
private static readonly string DiscSectorEncoderHint = "GDEmuExporterDiscSectorEncoderHint";
private BinaryPatcher binaryPatcher = new BinaryPatcher();
private DiscSectorEncoder discSectorEncoder = new DiscSectorEncoder();
public event AsyncOperationProgressChangedEventHandler ConversionProgressChanged
{
add => this.AsyncOperationProgressChanged += value;
remove => this.AsyncOperationProgressChanged -= value;
}
public event AsyncOperationCompletedEventHandler ConversionCompleted
{
add => this.AsyncOperationCompleted += value;
remove => this.AsyncOperationCompleted -= value;
}
public GDEmuConverter()
{
}
public GDEmuConverter(IContainer container)
: base(container)
{
}
public void ConvertAsync(
IDiscFileSystem GDIImageFile,
GDEmuExportOptions ExportOptions,
object taskId)
{
AsyncOperation asyncOperation = this.CreateAsyncOperation(taskId);
new GDEmuConverter.FileConverterWorkerEventHandler(this.FileConverterWorker).BeginInvoke(GDIImageFile, ExportOptions, asyncOperation, (AsyncCallback) null, (object) null);
}
private void FileConverterWorker(
IDiscFileSystem GDIImageFile,
GDEmuExportOptions ExportOption,
AsyncOperation asyncOp)
{
Exception exception = (Exception) null;
HashSet<DiscTrackCopyInfo> trackOutputFiles = this.GetTrackOutputFiles(GDIImageFile, ExportOption);
List<string> stringList = new List<string>();
this.CheckForFileConflict(ExportOption, trackOutputFiles, asyncOp);
if (this.TaskCanceled(asyncOp))
{
this.DoExtractionCleanupIfNeeded(stringList.ToArray(), exception, asyncOp);
this.ReportCompletion(ExportOption.OutputPath, exception, asyncOp);
}
else
{
long requiredSpaceInBytes = this.ComputeRequiredSpaceInBytes(trackOutputFiles);
long ofBytesToExtract = this.ComputeNumberOfBytesToExtract(trackOutputFiles);
long totalNumberOfBytesRemaining = ofBytesToExtract;
try
{
this.CheckForEnoughFreeDiscSpace(requiredSpaceInBytes, ExportOption.OutputPath);
GDICreator.CreateGDIFile(GDIImageFile.AllTracks, ExportOption.GetOutputGDIFilePath());
stringList.Add(ExportOption.GetOutputGDIFilePath());
foreach (DiscTrackCopyInfo track in trackOutputFiles)
{
if (!this.TaskCanceled(asyncOp))
{
stringList.Add(track.DestinationTrack.FileName);
totalNumberOfBytesRemaining = this.CopyTrack(track, ofBytesToExtract, totalNumberOfBytesRemaining, asyncOp);
}
else
break;
}
if (!this.TaskCanceled(asyncOp))
this.ApplyExportPatches(GDIImageFile, ExportOption, trackOutputFiles, asyncOp);
}
catch (Exception ex)
{
exception = ex;
UserProcessBase.logger.ErrorFormat("Unable to copy the track: {0}", (object) exception);
}
this.DoExtractionCleanupIfNeeded(stringList.ToArray(), exception, asyncOp);
this.ReportCompletion(ExportOption.OutputPath, exception, asyncOp);
}
}
private long ComputeNumberOfBytesToExtract(HashSet<DiscTrackCopyInfo> tracks)
{
long num = 0;
foreach (DiscTrackCopyInfo track in tracks)
num += track.SourceTrack.Length;
return num;
}
private long ComputeRequiredSpaceInBytes(HashSet<DiscTrackCopyInfo> tracks)
{
long num = 0;
foreach (DiscTrackCopyInfo track in tracks)
{
FileInfo fileInfo = new FileInfo(track.DestinationTrack.FileName);
num += track.SourceTrack.Length;
if (fileInfo.Exists)
num -= fileInfo.Length;
}
return num;
}
private void CheckForEnoughFreeDiscSpace(long requiredSpaceInBytes, string outputPath)
{
if (requiredSpaceInBytes > new DriveInfo(outputPath.Substring(0, 3)).AvailableFreeSpace)
{
UserProcessBase.logger.ErrorFormat("Extraction requires {0} bytes of free disc space in drive {1}", (object) requiredSpaceInBytes, (object) outputPath.Substring(0, 3));
throw new IOException("Not enough free disc space!");
}
}
private void CheckForFileConflict(
GDEmuExportOptions exportOptions,
HashSet<DiscTrackCopyInfo> inputFiles,
AsyncOperation asyncOp)
{
List<string> stringList = new List<string>();
if (File.Exists(exportOptions.GetOutputGDIFilePath()))
stringList.Add(exportOptions.GetOutputGDIFilePath());
foreach (DiscTrackCopyInfo inputFile in inputFiles)
{
if (File.Exists(inputFile.DestinationTrack.FileName))
stringList.Add(inputFile.DestinationTrack.FileName);
}
if (stringList.Count == 0)
return;
this.AskForUserConsent(GDEmuConverter.GetNotifyFileConflictEventArgs(stringList.ToArray(), asyncOp), asyncOp);
}
private long CopyTrack(
DiscTrackCopyInfo track,
long totalNumberOfBytesToExtract,
long totalNumberOfBytesRemaining,
AsyncOperation asyncOp)
{
using (System.IO.Stream fileInputStream = track.SourceTrack.FileInputStream)
{
using (System.IO.Stream fileOutputStream = track.DestinationTrack.FileOutputStream)
{
long length = fileInputStream.Length;
byte[] buffer = new byte[GDEmuConverter.OutputFileStreamBuffer];
while (length > 0L)
{
if (!this.TaskCanceled(asyncOp))
{
int count = fileInputStream.Read(buffer, 0, buffer.Length);
length -= (long) count;
totalNumberOfBytesRemaining -= (long) count;
fileOutputStream.Write(buffer, 0, count);
this.ReportProgress(GDEmuConverter.CreateProgressChangedEventArgs(track.SourceTrack.FileName, track.DestinationTrack.FileName, fileInputStream.Length, length, totalNumberOfBytesToExtract, totalNumberOfBytesRemaining, asyncOp), asyncOp);
}
else
break;
}
}
}
return totalNumberOfBytesRemaining;
}
private void ApplyExportPatches(
IDiscFileSystem GDIImageFile,
GDEmuExportOptions ExportOption,
HashSet<DiscTrackCopyInfo> OutputTrackFiles,
AsyncOperation asyncOp)
{
if (!ExportOption.ForceVGA && !ExportOption.RegionFree)
{
UserProcessBase.logger.Info((object) "No patch to apply");
}
else
{
this.UpdateViewForBinaryPatcherStep(asyncOp);
if (ExportOption.ForceVGA)
this.ApplyVGAPatch(OutputTrackFiles, asyncOp);
if (ExportOption.RegionFree)
this.ApplyRegionFreePatch(OutputTrackFiles, asyncOp);
if (this.TaskCanceled(asyncOp))
return;
this.CorrectModifiedSectors(OutputTrackFiles, asyncOp);
}
}
private void CorrectModifiedSectors(HashSet<DiscTrackCopyInfo> tracks, AsyncOperation asyncOp)
{
this.UpdateViewForDiscSectorEncoderStep(asyncOp);
foreach (DiscTrackCopyInfo track in tracks.Where<DiscTrackCopyInfo>((Func<DiscTrackCopyInfo, bool>) (track => track.SourceTrack.TrackData == TrackModeType.Data && track.SourceTrack.TrackSector.GetType() == typeof (CDROMMode1RawSector))))
{
this.ReportPatchOrErrorDataEncoderProgress(track, asyncOp);
if (this.TaskCanceled(asyncOp))
break;
using (System.IO.Stream fileOutputStream = track.DestinationTrack.FileOutputStream)
this.discSectorEncoder.EncodeMode1Sectors(fileOutputStream, track.ModifiedSectors);
}
}
private void ApplyPatches(DiscTrackCopyInfo track, BinaryPatch[] patches)
{
using (DiscSectorStream discSectorStream = new DiscSectorStream(track.DestinationTrack.FileOutputStream, track.DestinationTrack.TrackSector))
this.binaryPatcher.ApplyPatches((System.IO.Stream) discSectorStream, patches);
track.AddPatches(patches);
}
private void ApplyVGAPatch(HashSet<DiscTrackCopyInfo> OutputTrackFiles, AsyncOperation asyncOp)
{
DiscTrackCopyInfo track1 = OutputTrackFiles.First<DiscTrackCopyInfo>((Func<DiscTrackCopyInfo, bool>) (track => track.SourceTrack.Index == 1));
UserProcessBase.logger.InfoFormat("Applying VGA flag patches on {0}", (object) track1);
this.ReportPatchOrErrorDataEncoderProgress(track1, asyncOp);
this.ApplyPatches(track1, InitialProgramPatches.VGAFlagPatchesForTrack1);
DiscTrackCopyInfo track2 = OutputTrackFiles.First<DiscTrackCopyInfo>((Func<DiscTrackCopyInfo, bool>) (track => track.SourceTrack.Index == 3));
UserProcessBase.logger.InfoFormat("Applying VGA flag patches on {0}", (object) track2);
this.ReportPatchOrErrorDataEncoderProgress(track2, asyncOp);
this.ApplyPatches(track2, InitialProgramPatches.VGAFlagPatchesForTrack3);
}
private void ApplyRegionFreePatch(
HashSet<DiscTrackCopyInfo> OutputTrackFiles,
AsyncOperation asyncOp)
{
DiscTrackCopyInfo track1 = OutputTrackFiles.First<DiscTrackCopyInfo>((Func<DiscTrackCopyInfo, bool>) (track => track.SourceTrack.Index == 1));
UserProcessBase.logger.InfoFormat("Applying region free patches on {0}", (object) track1);
this.ReportPatchOrErrorDataEncoderProgress(track1, asyncOp);
this.ApplyPatches(track1, InitialProgramPatches.RegionFreePatchesForTrack1);
DiscTrackCopyInfo track2 = OutputTrackFiles.First<DiscTrackCopyInfo>((Func<DiscTrackCopyInfo, bool>) (track => track.SourceTrack.Index == 3));
UserProcessBase.logger.InfoFormat("Applying region free patches on {0}", (object) track2);
this.ReportPatchOrErrorDataEncoderProgress(track2, asyncOp);
this.ApplyPatches(track2, InitialProgramPatches.RegionFreePatchesForTrack3);
}
private HashSet<DiscTrackCopyInfo> GetTrackOutputFiles(
IDiscFileSystem GDIImageFile,
GDEmuExportOptions ExportOption)
{
HashSet<DiscTrackCopyInfo> discTrackCopyInfoSet = new HashSet<DiscTrackCopyInfo>();
foreach (IDiscTrack allTrack in GDIImageFile.AllTracks)
{
string newFileName = Path.Combine(ExportOption.OutputPath, allTrack.VirtualName);
discTrackCopyInfoSet.Add(DiscTrackCopyInfo.CreateFrom(allTrack, newFileName));
}
return discTrackCopyInfoSet;
}
private void DoExtractionCleanupIfNeeded(
string[] fileToDelete,
Exception exception,
AsyncOperation asyncOp)
{
if (!this.TaskCanceled(asyncOp) && exception == null)
return;
foreach (string path in fileToDelete)
{
if (File.Exists(path))
{
try
{
File.Delete(path);
}
catch (Exception ex)
{
UserProcessBase.logger.ErrorFormat("Unable to delete the file {0}: {1}", (object) path, (object) ex.Message);
}
}
}
}
private static UserProcessProgressChangedEventArgs CreateProgressChangedEventArgs(
string input,
string output,
long numberOfBytesToExtract,
long remainingBytesToExtract,
long totalNumberOfBytesToExtract,
long totalNumberOfBytesRemaining,
AsyncOperation asyncOp)
{
int progressPercentage = (int) ((double) (numberOfBytesToExtract - remainingBytesToExtract) / (double) numberOfBytesToExtract * 100.0);
int totalProgressPercentage = (int) ((double) (totalNumberOfBytesToExtract - totalNumberOfBytesRemaining) / (double) totalNumberOfBytesToExtract * 100.0);
return new UserProcessProgressChangedEventArgs(input, output, progressPercentage, totalProgressPercentage, asyncOp.UserSuppliedState);
}
private static UserProcessWaitingForUserConsentEventArgs GetNotifyFileConflictEventArgs(
string[] files,
AsyncOperation asyncOp)
{
return (UserProcessWaitingForUserConsentEventArgs) new UserProcessWaitingForUserConsentFileConflictEventArgs(GDEmuConverter.FileConflictQuestionTitle, GDEmuConverter.FileConflictQuestionContent, files, (object) asyncOp);
}
private void ReportPatchOrErrorDataEncoderProgress(
DiscTrackCopyInfo track,
AsyncOperation asyncOp)
{
this.ReportProgress(new UserProcessProgressChangedEventArgs(track.SourceTrack.FileName, track.DestinationTrack.FileName, 100, 100, asyncOp.UserSuppliedState), asyncOp);
}
private void UpdateViewForBinaryPatcherStep(AsyncOperation asyncOp) => this.UpdateUIView(UserProcessUpdateUIViewEventArgs.OneProgressBarWithoutPercentage(GDEmuConverter.BinaryPatcherHint, false), asyncOp);
private void UpdateViewForDiscSectorEncoderStep(AsyncOperation asyncOp) => this.UpdateUIView(UserProcessUpdateUIViewEventArgs.OneProgressBarWithoutPercentage(GDEmuConverter.DiscSectorEncoderHint, false), asyncOp);
private delegate void FileConverterWorkerEventHandler(
IDiscFileSystem imageFile,
GDEmuExportOptions ExportOption,
AsyncOperation asyncOp);
}
}

View file

@ -0,0 +1,22 @@
// Decompiled with JetBrains decompiler
// Type: SEGATools.GDEmu.GDEmuExportOptions
// Assembly: SEGATools, Version=1.0.3.0, Culture=neutral, PublicKeyToken=611be24fdeb07e08
// MVID: D631183F-57B1-40A1-B502-5364D288307A
// Assembly location: SEGATools.dll
using System.IO;
namespace SEGATools.GDEmu
{
public class GDEmuExportOptions
{
private static readonly string GDEMU_DEFAULT_DISC_IMAGE_FILE_NAME = "disc.gdi";
public bool RegionFree;
public bool ForceVGA;
public string OutputPath;
public string GDIFileName => GDEmuExportOptions.GDEMU_DEFAULT_DISC_IMAGE_FILE_NAME;
public string GetOutputGDIFilePath() => Path.Combine(this.OutputPath, this.GDIFileName);
}
}

View file

@ -0,0 +1,31 @@
// Decompiled with JetBrains decompiler
// Type: SEGATools.GDEmu.GDICreator
// Assembly: SEGATools, Version=1.0.3.0, Culture=neutral, PublicKeyToken=611be24fdeb07e08
// MVID: D631183F-57B1-40A1-B502-5364D288307A
// Assembly location: SEGATools.dll
using SEGATools.DiscFileSystem;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace SEGATools.GDEmu
{
public class GDICreator
{
public static void CreateGDIFile(List<IDiscTrack> Tracks, string OutputGDIFile)
{
List<IDiscTrack> list = Tracks.OrderBy<IDiscTrack, uint>((Func<IDiscTrack, uint>) (track => track.LogicalBlockAddress)).ToList<IDiscTrack>();
using (StreamWriter streamWriter = new StreamWriter(OutputGDIFile))
{
streamWriter.WriteLine(list.Count);
for (int index = 0; index < list.Count; ++index)
{
IDiscTrack discTrack = list[index];
streamWriter.WriteLine("{0} {1} {2} {3} {4} {5}", (object) (index + 1), (object) discTrack.LogicalBlockAddress, (object) (short) discTrack.TrackData, (object) discTrack.TrackSector.Size, (object) discTrack.VirtualName, (object) discTrack.Offset);
}
}
}
}
}