protected async Task InternalCreateIRD(string savePath, CancellationToken cancellation, string isoPath = null) { byte[] buffer = new byte[Utilities.SectorSize]; List <FileHash> fileList = new List <FileHash>(); try { // First, get the partition table of this iso using (Stream fs = Open()) { if (fs == null) { return; } PS3CDReader reader = new PS3CDReader(fs); List <DirectoryMemberInformation> files = reader.Members.Where(d => d.IsFile).Distinct().ToList(); StartOfDataSector = files.First().StartSector; EndOfDataSector = files.Last().StartSector + files.Last().TotalSectors; var updateFile = files.FirstOrDefault( d => d.Path.Equals("/PS3_UPDATE/PS3UPDAT.PUP", StringComparison.OrdinalIgnoreCase)); long updateOffset = updateFile != null ? updateFile.StartSector * Utilities.SectorSize : 0; fileList.AddRange(files.Select(d => new FileHash(d.StartSector, d.Length))); if (cancellation.IsCancellationRequested) { return; } IrdFile irdFile = IrdFile.New(); using (Stream s = reader.OpenFile("PS3_GAME\\PARAM.SFO", FileMode.Open, FileAccess.Read)) { ParamSfo sfo = ParamSfo.Load(s); irdFile.AppVersion = sfo.GetStringValue("APP_VER"); irdFile.GameVersion = sfo.GetStringValue("VERSION"); irdFile.GameID = sfo.GetStringValue("TITLE_ID"); irdFile.GameName = sfo.GetStringValue("TITLE"); } Interaction.Instance.ReportMessage("Processing " + (string.IsNullOrEmpty(irdFile.GameName) ? irdFile.GameID : irdFile.GameName)); irdFile.UpdateVersion = Utilities.FindUpdateVersion(fs, updateOffset); using (FileStream isoStream = string.IsNullOrEmpty(isoPath) ? null : new FileStream(isoPath, FileMode.Create, FileAccess.Write)) { if (isoStream != null) { isoStream.SetLength(TotalSectors * Utilities.SectorSize); } using (IOStream ioStream = new IOStream(fs, isoStream)) { ioStream.Seek(0, SeekOrigin.Begin); // Read the header, until StartOfDataSector (in sectors) irdFile.Header = new MemoryStream(); for (int i = 0; i < StartOfDataSector; i++) { int bytesRead = ioStream.Read(buffer, 0, buffer.Length); irdFile.Header.Write(buffer, 0, bytesRead); Interaction.Instance.ReportProgress(i); if (cancellation.IsCancellationRequested) { return; } } irdFile.ExtractAuthData(); // Fix the regions for the actual interesting data Regions.First().Start = (uint)StartOfDataSector; Regions.First().Length -= (uint)StartOfDataSector; Regions.Last().Length = (uint)EndOfDataSector - Regions.Last().Start; // Now, we should calculate the md5 sums of all regions Interaction.Instance.ReportMessage("Calculating hashes for " + Regions.Length + " regions."); for (int i = 0; i < Regions.Length; i++) { // Calculate the hash Interaction.Instance.ReportMessage( "Calculate hash for region " + i + " (" + Regions[i].Start.ToString("X2") + "-" + Regions[i].End.ToString("X2") + ")"); ioStream.Seek(Regions[i].Start * Utilities.SectorSize, SeekOrigin.Begin); using (FileHashStream fhs = new FileHashStream(fileList, Regions[i].Start)) { await Regions[i].CopyRegion(cancellation, ioStream, fhs); if (cancellation.IsCancellationRequested) { return; } irdFile.RegionHashes.Add(Regions[i].SourceHash); Interaction.Instance.ReportMessage("Region " + i + " hash: " + Regions[i].SourceHash.AsString()); } } ioStream.Seek(EndOfDataSector * Utilities.SectorSize, SeekOrigin.Begin); irdFile.Footer = new MemoryStream(); for (long i = EndOfDataSector; i < TotalSectors; i++) { int bytesRead = ioStream.Read(buffer, 0, buffer.Length); irdFile.Footer.Write(buffer, 0, bytesRead); Interaction.Instance.ReportProgress((int)(ioStream.Position / Utilities.SectorSize)); if (cancellation.IsCancellationRequested) { return; } } } } irdFile.FileHashes = fileList.ToDictionary(t => t.StartSector, t => t.Hash); irdFile.Save(savePath); Interaction.Instance.ReportMessage("All done, IRD file saved to " + savePath); } } catch (BadReadException e) { Interaction.Instance.ReportMessage(e.Message, ReportType.Fail); } catch (AuthenticationException e) { Interaction.Instance.ReportMessage(e.Message, ReportType.Fail); } }
public static IrdFile Load(string path) { Exception ex = null; bool update_ird_file = false; IrdFile ird = new IrdFile(); try { ird.FullPath = path; using (Stream s = Open(path)) { using (CrcCalculatorStream crc = new CrcCalculatorStream(s, true)) { using (BinaryReader br = new BinaryReader(crc)) { // Read magic byte[] magic = br.ReadBytes(4); if (magic.AsString() != MAGIC.AsString()) { ex = new FileLoadException("Invalid IRD file", path); throw ex; } // Read version ird.Version = br.ReadByte(); if (ird.Version != IrdVersion) { if (!CompatibleVersions.Any(v => v == ird.Version)) { ex = new FileLoadException("Unsupported IRD file version (Found version " + ird.Version + ")", path); throw ex; } update_ird_file = true; } ird.gameId = Encoding.ASCII.GetString(br.ReadBytes(9)).Trim('\0'); ird.GameName = br.ReadString(); // Read version of update file byte[] update = br.ReadBytes(4); ird.UpdateVersion = Encoding.ASCII.GetString(update).Trim('\0'); // Read the gameversion byte[] gameVersion = br.ReadBytes(5); ird.GameVersion = Encoding.ASCII.GetString(gameVersion).Trim('\0'); byte[] appVersion = br.ReadBytes(5); ird.AppVersion = Encoding.ASCII.GetString(appVersion).Trim('\0'); // Read header and footer sectors ird.Header = br.Uncompress(); ird.Footer = br.Uncompress(); // Read region hashes int amountOfHashes = br.ReadByte(); for (int i = 0; i < amountOfHashes; i++) { byte[] hash = br.ReadBytes(0x10); ird.RegionHashes.Add(hash); } // Read file hashes int amountOfFiles = br.ReadInt32(); ird.FileHashes = new Dictionary <long, byte[]>(amountOfFiles); for (int i = 0; i < amountOfFiles; i++) { long sector = br.ReadInt64(); byte[] hash = br.ReadBytes(0x10); ird.FileHashes.Add(sector, hash); } // Read amount of attachments and extra config fields int extraConfig = br.ReadUInt16(); int attachments = br.ReadUInt16(); // Yes, we don't use these for now, but we might in the future ird.Data1 = br.ReadBytes(0x10); ird.Data2 = br.ReadBytes(0x10); ird.PIC = br.ReadBytes(0x73); } ird.Crc = (uint)crc.Crc; } byte[] crcValue = new byte[4]; s.Read(crcValue, 0, 4); if (ird.Crc != BitConverter.ToUInt32(crcValue, 0)) { ex = new FileLoadException("Invalid CRC value in the IRD file", path); throw ex; } } if (update_ird_file) { Interaction.Instance.ReportMessage("Updating IRD file to latest version: " + Path.GetFileName(path)); ird.Save(path); } return(ird); } catch (ZlibException) { // Annoying bug in the zlib decompression of Ionic.Zip if (ex != null) { throw ex; } return(ird); } catch (EndOfStreamException e) { throw new FileLoadException("Unexpected end of IRD file", path, e); } }