private void WriteFooter(Stream fs, IrdFile irdFile, bool isValidFile, CancellationToken token) { // Fix identifier long pos = fs.Position; fs.Seek(0xf70, SeekOrigin.Begin); byte[] e3kb = isValidFile ? Utilities.Encrypted3KBuild : Utilities.Encrypted3KFailedBuild; fs.Write(e3kb, 0, e3kb.Length); fs.Seek(pos, SeekOrigin.Begin); irdFile.Footer.Seek(0, SeekOrigin.Begin); fs.Seek(-irdFile.Footer.Length, SeekOrigin.End); // Seek a small bit until the end of the last file, and the start of the footer byte[] buffer = new byte[Utilities.SectorSize]; for (int i = 0; i < irdFile.Footer.Length; i += buffer.Length) { irdFile.Footer.Read(buffer, 0, buffer.Length); fs.Write(buffer, 0, buffer.Length); Interaction.Instance.ReportProgress((int)(fs.Position / Utilities.SectorSize)); if (token.IsCancellationRequested) { return; } } }
private void ParseTableOfContents(IrdFile irdFile) { using (BinaryReader br = new BinaryReaderExt(irdFile.Header, Encoding.ASCII, true)) { irdFile.Header.Seek(0, SeekOrigin.Begin); uint amountOfRegions = br.ReadUInt32().Swap(); br.BaseStream.Position = 8; uint start = br.ReadUInt32().Swap(); for (uint i = 0; i < (2 * amountOfRegions) - 1; i++) { br.BaseStream.Position = (i + 3) * 4; uint next = br.ReadUInt32().Swap(); Regions.Add(i % 2 == 0 ? (Region) new PlainRegion(i, false, true, true, start, next) : new DecryptedRegion(i, irdFile.Data1, randomData2, start, next, false)); start = next; } } irdFile.Header.Seek(0, SeekOrigin.Begin); PS3CDReader reader = new PS3CDReader(irdFile.Header); FirstContentSector = reader.Members.First(d => d.IsFile).StartSector; LastContentSector = reader.Members.Last().StartSector + reader.Members.Last().TotalSectors - 1; cdBuilder.ExtentInfo = reader.Members; }
private bool CheckFiles(CancellationToken cancellation, IrdFile irdFile) { bool retval = true; int sectors = 0; // ExtentInfo contains all files from the original ISO. That means that a file that is // missing, it will still be available in the ExtentInfo. foreach (var grp in cdBuilder.ExtentInfo.Where(d => d.IsFile).GroupBy(l => l.StartSector)) { var dmi = grp.First(); byte[] hash; if (dmi.Stream != null) { hash = dmi.Stream.GetMd5(cancellation, 0, ref sectors); dmi.Stream.Seek(0, SeekOrigin.Begin); } else { string filename = System.IO.Path.Combine(Path, dmi.Path.Substring(1)); if (!File.Exists(filename)) { Interaction.Instance.ReportMessage("File not found: " + dmi.Path); retval = false; continue; } hash = filename.GetMd5(cancellation, dmi.Length, ref sectors); } if (cancellation.IsCancellationRequested) { break; } // Find the corresponding file KeyValuePair <long, byte[]> irdHash = irdFile.FileHashes.FirstOrDefault(f => f.Key == dmi.StartSector); if (irdHash.Value == null) { continue; } if (hash.AsString() != irdHash.Value.AsString()) { Interaction.Instance.ReportMessage("Invalid hash of file: " + dmi.Path); retval = false; } if (cancellation.IsCancellationRequested) { break; } } return(retval); }
private bool CheckParams(IrdFile irdFile) { // Check the game id ParamSfo sfo = ParamSfo.Load(System.IO.Path.Combine(Path, @"PS3_GAME\PARAM.SFO")); string gameID = sfo.GetStringValue("TITLE_ID"); if (gameID != irdFile.GameID) { Interaction.Instance.ReportMessage( string.Format("This IRD file is for another game (IRD File: {0}, JB Rip: {1})", irdFile.GameID, gameID), ReportType.Fail); return(false); } // Check the game version string gameVersion = sfo.GetStringValue("VERSION"); if (gameVersion != irdFile.GameVersion) { Interaction.Instance.ReportMessage( string.Format("This IRD file is for another release version (IRD File: {0}, JB Rip: {1})", irdFile.GameVersion, gameVersion), ReportType.Fail); return(false); } // Check the game version string appVersion = sfo.GetStringValue("APP_VER"); if (appVersion != irdFile.AppVersion) { Interaction.Instance.ReportMessage( string.Format("This IRD file is for another application version (IRD File: {0}, JB Rip: {1})", irdFile.AppVersion, appVersion), ReportType.Fail); return(false); } return(true); }
private void WriteHeader(Stream fs, IrdFile irdFile, byte[] data2, CancellationToken token) { irdFile.Header.Seek(0, SeekOrigin.Begin); byte[] buffer = new byte[Utilities.SectorSize]; for (int i = 0; i < irdFile.Header.Length; i += buffer.Length) { irdFile.Header.Read(buffer, 0, buffer.Length); fs.Write(buffer, 0, buffer.Length); Interaction.Instance.ReportProgress((int)(fs.Position / Utilities.SectorSize)); if (token.IsCancellationRequested) { return; } } // Write the K3YIdentification, Data1, Data2 and PIC data back fs.Seek(0xF70, SeekOrigin.Begin); fs.Write(Utilities.Encrypted3KBuild, 0, Utilities.Encrypted3KBuild.Length); fs.Write(irdFile.Data1, 0, irdFile.Data1.Length); fs.Write(irdFile.Data2, 0, data2.Length); fs.Write(irdFile.PIC, 0, irdFile.PIC.Length); }
public async Task <bool> CreateIso(CancellationToken cancellation) { try { // Get the JB directory Path = await Interaction.Instance.GetJBDirectory(); if (string.IsNullOrEmpty(Path)) { return(false); } if (!IsValidDirectory(Path)) { Interaction.Instance.ShowMessageDialog(Resources.NotAValidJBDirectory); return(false); } if (!Path.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture))) { Path += System.IO.Path.DirectorySeparatorChar; } // Get the resulting iso filename string savePath = await Interaction.Instance.GetSaveIsoPath(); if (string.IsNullOrEmpty(savePath)) { return(false); } IrdFile irdFile; try { string irdPath = await Interaction.Instance.GetIrdFile(); if (string.IsNullOrEmpty(irdPath)) { return(false); } irdFile = IrdFile.Load(irdPath); } catch (FileLoadException e) { Interaction.Instance.ReportMessage(e.Message); return(false); } if (!CheckParams(irdFile)) { return(false); } if (!(await ValidateOrGetUpdate(irdFile, cancellation))) { return(false); } Interaction.Instance.TaskBegin(); randomData2 = MakeData2Random(irdFile.Data2); // Okay, got that figured out, now we have to parse the partition table // and get the regions Interaction.Instance.ReportMessage("Parsing IRD file"); ParseTableOfContents(irdFile); cdBuilder.TotalLength = ((LastContentSector + 1) * Utilities.SectorSize) + irdFile.Footer.Length; bool isValidFile; Interaction.Instance.SetProgressMaximum((int)(LastContentSector - FirstContentSector)); Interaction.Instance.ReportMessage("Checking files..."); await AddFiles(cancellation); Interaction.Instance.ReportProgress(0); // Reset progress IsoCryptoClass icc = new IsoCryptoClass(); try { icc.AnalyseISOBuilder(this); } catch (Exception e) { Interaction.Instance.ReportMessage(e.Message); return(false); } // Verify that the IRD and choosen game directory are the same if (irdFile.GameID != icc.GameID) { Interaction.Instance.ReportMessage("This IRD file is not valid for this JB directory"); return(false); } Interaction.Instance.ReportProgress(0); Interaction.Instance.ReportMessage("Validating files..."); using (Stream s = Build()) { Interaction.Instance.SetProgressMaximum(FilesEndSector - FilesStartSector); bool validFiles = await TaskEx.Run(() => CheckFiles(cancellation, irdFile)); if (!validFiles) { if (cancellation.IsCancellationRequested) { return(false); } // Ask if the user wants to continue Interaction.Instance.ReportMessage("Invalid hashes found, will continue anyway."); } if (cancellation.IsCancellationRequested) { return(false); } Interaction.Instance.ReportProgress(0); Interaction.Instance.ReportMessage(string.Format("Creating ISO '{0}...'", savePath)); // Fix regions to write (skip header, and make last region shorter icc.Regions.First().Start = (uint)FirstContentSector; icc.Regions.First().Length -= (uint)FirstContentSector; icc.Regions.Last().Length = (uint)(LastContentSector - icc.Regions.Last().Start) + 1; // Skip partition tables and all, we write those ourselves s.Seek(FirstContentSector * Utilities.SectorSize, SeekOrigin.Begin); using (FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.ReadWrite)) { WriteHeader(fs, irdFile, randomData2, cancellation); if (cancellation.IsCancellationRequested) { return(false); } fs.Seek(FirstContentSector * Utilities.SectorSize, SeekOrigin.Begin); isValidFile = await icc.DoWork(s, fs, cancellation, true, irdFile); if (cancellation.IsCancellationRequested) { return(false); } WriteFooter(fs, irdFile, isValidFile, cancellation); if (cancellation.IsCancellationRequested) { return(false); } if (!isValidFile) { Interaction.Instance.SetProgressError(); } } } Interaction.Instance.ReportMessage( string.Format("All complete, resulting ISO {0} the original.", isValidFile ? "MATCHES" : "DOES NOT MATCH")); } catch (PS3BuilderException) { Interaction.Instance.TaskComplete(); Interaction.Instance.ReportMessage("Create ISO aborted due to previous errors."); return(false); } catch (Exception e) { Interaction.Instance.TaskComplete(); Interaction.Instance.ReportMessage(e.Message); return(false); } Interaction.Instance.TaskComplete(); return(true); }
private async Task <bool> ValidateOrGetUpdate(IrdFile irdFile, CancellationToken cancellation) { // All zeroes, then no update is available (release date games only!) if (irdFile.UpdateVersion != "0000") { // Check the PS3Update version string ps3updatePath = System.IO.Path.Combine(Path, "PS3_UPDATE", "PS3UPDAT.PUP"); bool invalidUpdate = false, downloadUpdate = false; if (!File.Exists(ps3updatePath)) { invalidUpdate = true; downloadUpdate = await Interaction.Instance.DownloadUpdate( string.Format( "The file PS3UPDAT.PUP is missing from your JB rip. Automatically try and download version {0}?", irdFile.UpdateVersion)); } else { using (FileStream fs = new FileStream(ps3updatePath, FileMode.Open, FileAccess.Read)) { string version = Utilities.FindUpdateVersion(fs, 0); if (version == null || version != irdFile.UpdateVersion) { invalidUpdate = true; string msg = version != null ? string.Format( "The file PS3UPDAT.PUP is version {0}, while the original disc contains version {1}. Either continue (and accept the invalid hash), or replace the PS3UPDAT.PUP with the correct version.\nAutomatically try to download the correct update file?", version, irdFile.UpdateVersion) : string.Format( "The file PS3UPDAT.PUP is either empty, or not a valid file. The original disc contains version {0}. Automatically try to download the correct update file?", irdFile.UpdateVersion); downloadUpdate = await Interaction.Instance.DownloadUpdate(msg); } } } if (invalidUpdate) { if (!downloadUpdate) { Interaction.Instance.ReportMessage( "The PS3UPDAT.PUP file is missing or incorrect, and you've choosen to not download the correct file. Download the file manually. The required version is " + irdFile.UpdateVersion, ReportType.Fail); Interaction.Instance.ReportMessage("Create ISO aborted.", ReportType.Fail); return(false); } // Download the correct update Interaction.Instance.TaskBegin(true); Interaction.Instance.ReportMessage("Download update file..."); bool success = await UpdateDownloader.Download(irdFile.UpdateVersion, irdFile.GameID, ps3updatePath, cancellation); if (cancellation.IsCancellationRequested) { return(false); } if (success) { Interaction.Instance.ReportMessage("Updatefile successfully downloaded.", ReportType.Success); } else { Interaction.Instance.ReportMessage( "Failed to download the update file. You should try to locate the update file yourself.", ReportType.Fail); return(false); } } } return(true); }