public long Preserve(long offset, byte[] decrypted, long size) { int x = (int)(offset / WiiPartitionSection.GroupSize); int byt = x / 8; int bit = 1 << (7 - (x % 8)); _flags.Write8(byt, (byte)(_flags.Read8(byt) | bit)); long written = 0; for (int i = 0; i < size; i += 0x8000) { _hashes.Write(decrypted, i, 0x400); written += 0x400; } return(written); }
internal void Initialise(WiiPartitionGroupSection firstSection) { _firstSection = firstSection; IsEncrypted = firstSection.IsEncrypted; MemorySection ms = new MemorySection(firstSection.Decrypted); this.Id = ms.ReadString(0x400, 4); this.DiscNo = (int)ms.Read8(0x406); if (this.Stream != null) { this.Stream.ChangeJunk(this.DiscOffset + _dataOffset, this.Id, this.DiscNo, PartitionDataSize); } if (this.Id != "\0\0\0\0") { _dolOffset = ms.ReadUInt32B(0x820) * 4L; //+400 to skip hashes FstOffset = ms.ReadUInt32B(0x824) * 4L; FstSize = ms.ReadUInt32B(0x828) * 4L; } }
private long partitionWrite(Stream inStream, NCrc crc, Stream target, WiiPartitionSection pHdr, Context ctx, Coordinator pc, NkitInfo imageInfo, ScrubManager scrub, WiiHashStore hashes, long fstFileAlignment) { #if DEHASH return(pHdr.NewPartitionDataLength = inStream.Copy(target, pHdr.PartitionDataLength, null)); #elif DECRYPT inStream.Copy(target, pHdr.PartitionLength, null); return(pHdr.NewPartitionDataLength = pHdr.PartitionDataLength); #endif MemorySection hdr = MemorySection.Read(inStream, 0x440); //ProgressResult result = ctx.Result; long mlt = 4L; //GC 1L long logicalSize = pHdr.PartitionDataLength; //GC: ctx.ImageLength; long physicalSize = pHdr.PartitionDataLength; //GC: result.ImageInfo.IsoSize; string junkId = hdr.ReadString(0, 4); //bool write = true; List <string> addedFiles = new List <string>(); long srcPos; long dstPos = 0; JunkStream js = new JunkStream(junkId, hdr.Read8(6), logicalSize); try { if (junkId == "\0\0\0\0") { srcPos = hdr.Size; imageInfo.BytesData = srcPos; _log?.LogDetail("Null Partition ID, preserving partition as raw"); ConvertFile cf = new ConvertFile(logicalSize - hdr.Size, true) //Size isn't important for writing //result.ImageInfo.IsoSize { FstFile = new FstFile(null) { DataOffset = hdr.Size, Offset = hdr.Size, Length = 0 }, }; long nullsPos = 0; target.Write(hdr.Data, 0, (int)hdr.Size); //0x400 target.Write(pHdr.Header.Data, 0x2bc, 4); //copy the original partition length dstPos += 0x440 + 4 + NkitFormat.ProcessGap(ref nullsPos, cf, ref srcPos, inStream, js, true, scrub, target, _log); } else { hdr.WriteString(0x200, 8, "NKIT v01"); hdr.WriteUInt32B(0x210, (uint)(pHdr.PartitionLength / mlt)); MemorySection fst; List <JunkDiff> junkDiffs = new List <JunkDiff>(); long mainDolAddr = hdr.ReadUInt32B(0x420) * mlt; //############################################################################ //# READ DISC START target.Write(hdr.Data, 0, (int)hdr.Size); inStream.Copy(target, (hdr.ReadUInt32B(0x424) * mlt) - hdr.Size); //read fst with 4 byte boundary fst = MemorySection.Read(inStream, (hdr.ReadUInt32B(0x428) * mlt) + (((hdr.ReadUInt32B(0x428) * mlt) % 4 == 0 ? 0 : 4 - ((hdr.ReadUInt32B(0x428) * mlt) % 4)))); crc.Snapshot(junkId + " PrtHdr"); target.Write(fst.Data, 0, (int)fst.Size); crc.Snapshot(junkId + " Fst"); target.Write(hashes.FlagsToByteArray(), 0, (int)hashes.FlagsLength); crc.Snapshot(junkId + " HashFlags"); srcPos = (hdr.ReadUInt32B(0x424) * mlt) + fst.Size; long nullsPos = srcPos + 0x1c; dstPos = srcPos + hashes.FlagsLength; //create as late as possible in case id is swaped - Dairantou Smash Brothers DX (Japan) (Taikenban), Star Wars - Rogue Squadron II (Japan) (Jitsuen-you Sample) string error; List <ConvertFile> conFiles = NkitFormat.GetConvertFstFiles(inStream, physicalSize, hdr, fst, false, fstFileAlignment, out error); imageInfo.BytesData = srcPos; if (conFiles == null) { if (error != null) { _log?.LogDetail(error); } ConvertFile cf = new ConvertFile(pHdr.PartitionDataLength - srcPos, true) //Size isn't important for writing //result.ImageInfo.IsoSize { FstFile = new FstFile(null) { DataOffset = hdr.ReadUInt32B(0x424), Offset = hdr.ReadUInt32B(0x424), Length = (int)fst.Size }, }; dstPos += NkitFormat.ProcessGap(ref nullsPos, cf, ref srcPos, inStream, js, true, scrub, target, _log); } else { //############################################################################ //# WRITE THE FILESYSTEM List <ConvertFile> missing; NkitFormat.NkitWriteFileSystem(ctx, imageInfo, mlt, inStream, ref srcPos, ref dstPos, hdr, fst, ref mainDolAddr, target, nullsPos, js, conFiles, out missing, scrub, pHdr.PartitionDataLength, _log); dstPos += hashes.HashesToStream(target); if (missing.Count != 0) { _log?.LogDetail(string.Format("{0} Junk File{1} Removed (Files listed in the FST, but not in the image)", missing.Count.ToString(), missing.Count == 1 ? "" : "s")); foreach (ConvertFile cf in missing) { _log?.LogDebug(string.Format("File content is Junk {0}: {1} - Size: {2}", cf.FstFile.DataOffset.ToString("X8"), cf.FstFile.Name, cf.FstFile.Length)); } } crc.Crcs[crc.Crcs.Length - 1].PatchData = hashes.FlagsToByteArray(); crc.Crcs[crc.Crcs.Length - 1].PatchCrc = Crc.Compute(crc.Crcs[crc.Crcs.Length - 2].PatchData); crc.Crcs[crc.Crcs.Length - 2].PatchData = fst.Data; crc.Crcs[crc.Crcs.Length - 2].PatchCrc = Crc.Compute(fst.Data); } } } catch (Exception ex) { throw new HandledException(ex, "NkitWriterGc.Write - Convert"); } return(dstPos); }
public void Write(Context ctx, Stream inStream, Stream outStream, Coordinator pc) { try { long mlt = 1L; //for Wii: 4L long imageSize = pc.OutputSize; //for Wii: pHdr.PartitionDataLength pc.WriterCheckPoint1WriteReady(out string junkId); //wait until read has written the header and set the length List <string> addedFiles = new List <string>(); NCrc crc = new NCrc(); long srcPos; long dstPos = 0; MemorySection hdr = MemorySection.Read(inStream, 0x440); string id8 = string.Concat(hdr.ReadString(0, 6), hdr.Data[6].ToString("X2"), hdr.Data[7].ToString("X2")); if (junkId == null) { junkId = ctx.Settings.JunkIdSubstitutions.FirstOrDefault(a => a.Id8 == id8)?.JunkId; if (junkId != null) { _log?.LogDetail(string.Format("Using ID {0} for junk not image ID {1}", junkId, id8.Substring(0, 4))); } } if (junkId == null) { junkId = hdr.ReadString(0, 4); } MemorySection fst; List <JunkDiff> junkDiffs = new List <JunkDiff>(); long mainDolAddr = hdr.ReadUInt32B(0x420) * mlt; long fstFileAlignment = ctx?.Settings?.PreserveFstFileAlignment?.FirstOrDefault(a => a.Item1 == id8)?.Item2 ?? -1; CryptoStream target = new CryptoStream(outStream, crc, CryptoStreamMode.Write); //############################################################################ //# READ DISC START target.Write(hdr.Data, 0, (int)hdr.Size); crc.Snapshot("hdr.bin"); inStream.Copy(target, (hdr.ReadUInt32B(0x424) * mlt) - hdr.Size); crc.Snapshot("bi2.bin, appldr.bin, main.dol"); //read fst with 4 byte boundary fst = MemorySection.Read(inStream, (hdr.ReadUInt32B(0x428) * mlt) + (((hdr.ReadUInt32B(0x428) * mlt) % 4 == 0 ? 0 : 4 - ((hdr.ReadUInt32B(0x428) * mlt) % 4)))); target.Write(fst.Data, 0, (int)fst.Size); crc.Snapshot("fst.bin"); srcPos = (hdr.ReadUInt32B(0x424) * mlt) + fst.Size; long nullsPos = srcPos + 0x1c; dstPos = srcPos; //create as late as possible in case id is swaped - Dairantou Smash Brothers DX (Japan) (Taikenban), Star Wars - Rogue Squadron II (Japan) (Jitsuen-you Sample) JunkStream js = new JunkStream(junkId, hdr.Read8(6), NStream.FullSizeGameCube); List <ConvertFile> conFiles = NkitFormat.GetConvertFstFiles(inStream, imageSize, hdr, fst, true, fstFileAlignment, out string error); //Size isn't important for writing //result.ImageInfo.IsoSize NkitInfo nkitInfo = new NkitInfo { BytesData = srcPos, BytesGaps = 0, BytesJunkFiles = 0, BytesPreservationData = 0, BytesPreservationDiscPadding = 0 }; ScrubManager scrub = new ScrubManager(); if (conFiles == null) { if (error != null) { _log?.LogDetail(error); } ConvertFile cf = new ConvertFile(imageSize - srcPos, true) //Size isn't important for writing //result.ImageInfo.IsoSize { FstFile = new FstFile(null) { DataOffset = hdr.ReadUInt32B(0x424), Offset = hdr.ReadUInt32B(0x424), Length = (int)fst.Size }, }; NkitFormat.ProcessGap(ref nullsPos, cf, ref srcPos, inStream, js, true, scrub, target, _log); } else { //############################################################################ //# WRITE THE FILESYSTEM NkitFormat.NkitWriteFileSystem(ctx, nkitInfo, mlt, inStream, ref srcPos, ref dstPos, hdr, fst, ref mainDolAddr, target, nullsPos, js, conFiles, out List <ConvertFile> missing, scrub, imageSize, _log); if (missing.Count != 0) { _log?.LogDetail(string.Format("{0} Junk File{1} Removed (Files listed in the FST, but not in the image)", missing.Count.ToString(), missing.Count == 1 ? "" : "s")); foreach (ConvertFile cf in missing) { _log?.LogDebug(string.Format("File content is Junk {0}: {1} - Size: {2}", cf.FstFile.DataOffset.ToString("X8"), cf.FstFile.Name, cf.FstFile.Length)); } } } if (dstPos % 0x800 != 0) { long l = 0x800 - (dstPos % 0x800); ByteStream.Zeros.Copy(target, l); dstPos += l; nkitInfo.BytesPreservationDiscPadding += l; } crc.Snapshot("files"); NkitFormat.LogNkitInfo(nkitInfo, _log, hdr.ReadString(0, 4), true); pc.WriterCheckPoint2Complete(out NCrc readerCrcs, out uint validationCrc, hdr.Data, dstPos); //wait until reader has completed and get crc patches. hdr.WriteUInt32B(0x420, (uint)mainDolAddr); hdr.WriteString(0x200, 8, "NKIT v01"); //header and version hdr.WriteUInt32B(0x208, readerCrcs.FullCrc(true)); //original crc hdr.WriteUInt32B(0x210, (uint)imageSize); //result.ImageInfo.IsoSize); hdr.WriteString(0x214, 4, hdr.ReadString(0, 4) != junkId ? junkId : "\0\0\0\0"); crc.Crcs[0].PatchCrc = Crc.Compute(hdr.Data); crc.Crcs[0].PatchData = hdr.Data; crc.Crcs[2].PatchCrc = Crc.Compute(fst.Data); crc.Crcs[2].PatchData = fst.Data; hdr.WriteUInt32B(0x20C, CrcForce.Calculate(crc.FullCrc(true), dstPos, readerCrcs.FullCrc(true), 0x20C, 0)); //magic to force crc crc.Crcs[0].PatchCrc = Crc.Compute(hdr.Data); pc.WriterCheckPoint3ApplyPatches(crc, false, crc.FullCrc(true), crc.FullCrc(true), VerifyIsWrite, "NKit Written"); } catch (Exception ex) { throw pc.SetWriterException(ex, "NkitWriterGc.Write - Convert"); } }
public virtual OutputResults Process(Context ctx, NStream input, Stream output) { OutputResults results = new OutputResults() { Conversion = ctx.ConversionName, VerifyOutputResult = VerifyResult.Unverified, ValidateReadResult = VerifyResult.Unverified }; try { StreamCircularBuffer fs = null; _timer = new Timer { Interval = 250 }; _timer.Elapsed += (s, e) => { if (_timerRunning) { return; //keep processing } try { _timerRunning = true; _log.ProcessingProgress(((IProgress)fs)?.Value ?? 0); } catch { } finally { _timerRunning = false; } }; _timer.Enabled = true; long size; switch (_sizeMode) { case ProcessorSizeMode.Source: size = input.SourceSize; break; case ProcessorSizeMode.Stream: size = input.Length; break; case ProcessorSizeMode.Image: size = input.ImageSize; break; case ProcessorSizeMode.Recover: default: size = input.RecoverySize; break; } Coordinator pc = new Coordinator(ctx.ValidationCrc, Reader, Writer, size); pc.Started += (s, e) => { _timer.Enabled = true; results.AliasJunkId = e.AliasJunkId; }; pc.Completed += (s, e) => { _timer.Enabled = false; if (Writer is HashWriter) { results.OutputMd5 = e.Md5; results.OutputSha1 = e.Sha1; } else { MemorySection hdr = new MemorySection(e.Header ?? input.DiscHeader.Data); results.OutputTitle = hdr.ReadStringToNull(0x20, 0x60); results.OutputDiscNo = hdr.Read8(6); results.OutputDiscVersion = hdr.Read8(7); results.OutputId8 = string.Concat(hdr.ReadString(0, 6), results.OutputDiscNo.ToString("X2"), results.OutputDiscVersion.ToString("X2")); results.ProcessorMessage = e.ResultMessage; results.OutputCrc = e.PatchedCrc; results.IsRecoverable = e.IsRecoverable; if (e.ValidationCrc != 0) { results.ValidationCrc = e.ValidationCrc; results.ValidateReadResult = e.ValidationCrc == e.PatchedCrc ? VerifyResult.VerifySuccess : VerifyResult.VerifyFailed; } if (!(Writer is VerifyWriter)) { results.OutputSize = e.OutputSize; //never store the verify size } else { results.VerifyCrc = e.VerifyCrc; if (e.VerifyIsWrite) //e.ValidationCrc can be set from a previous process run { results.VerifyOutputResult = results.ValidationCrc == results.VerifyCrc ? VerifyResult.VerifySuccess : VerifyResult.VerifyFailed; } } } bool l9 = pc.Patches.Crcs.Any(a => a.Offset > 0xFFFFFFFFL || a.Length > 0xFFFFFFFFL); if (pc.ReaderCrcs != null) { foreach (CrcItem c in pc.ReaderCrcs.Crcs) { _log.LogDebug(string.Format("R-CRC {0} Before:{1} After:{2} L:{3} {4}", c.Offset.ToString(l9 ? "X9" : "X8"), c.Value.ToString("X8"), c.PatchCrc == 0 ? " " : c.PatchCrc.ToString("X8"), c.Length.ToString(l9 ? "X9" : "X8"), SourceFiles.CleanseFileName(c.Name))); } _log.LogDebug(string.Format("ReadCRC {0}Before:{1} After:{2}", l9 ? " " : "", pc.ReaderCrcs.FullCrc(false).ToString("X8"), pc.ReaderCrcs.FullCrc(true).ToString("X8"))); } if (pc.WriterCrcs != null) { foreach (CrcItem c in pc.WriterCrcs.Crcs) { _log.LogDebug(string.Format("W-CRC {0} Before:{1} After:{2} L:{3} {4}", c.Offset.ToString(l9 ? "X9" : "X8"), c.Value.ToString("X8"), c.PatchCrc == 0 ? " " : c.PatchCrc.ToString("X8"), c.Length.ToString(l9 ? "X9" : "X8"), SourceFiles.CleanseFileName(c.Name))); } _log.LogDebug(string.Format("WriteCRC {0}Before:{1} After:{2}", l9 ? " " : "", pc.WriterCrcs.FullCrc(false).ToString("X8"), pc.WriterCrcs.FullCrc(true).ToString("X8"))); } _log.ProcessingComplete(results.OutputSize, results.ProcessorMessage, true); }; try { _log.ProcessingStart(input.SourceSize, Title); using (fs = new StreamCircularBuffer(size, input, null, s => Reader.Read(ctx, input, s, pc))) //read in stream and write to circular buffer { Writer.Write(ctx, fs, output, pc); } } catch { if (pc.Exception != null) { throw pc.Exception; } if (fs.WriterException != null) { throw fs.WriterException; } throw; //writer exception } foreach (CrcItem crc in pc.Patches.Crcs.Where(a => a.PatchData != null || a.PatchFile != null)) { output.Seek(crc.Offset, SeekOrigin.Begin); if (crc.PatchFile == null) { output.Write(crc.PatchData, 0, (int)Math.Min(crc.Length, crc.PatchData.Length)); //PatchData might be larger } else { using (FileStream pf = File.OpenRead(crc.PatchFile)) { pf.Copy(output, pf.Length); ByteStream.Zeros.Copy(output, crc.Length - pf.Length); } } } } catch (Exception ex) { if (_timer != null) { _timer.Enabled = false; } try { _log.ProcessingComplete(results.OutputSize, results.ProcessorMessage, false); // force any log lines to be output - handy for diagnosis } catch { } throw new HandledException(ex, "Failed processing {0} -> {1}", Reader?.GetType()?.Name ?? "<null>", Writer?.GetType()?.Name ?? "<null>"); } finally { if (_timer != null) { _timer.Enabled = false; _timer = null; } } return(results); }
private ExtractResult extractFiles(string id, MemorySection hdr, Stream inStream, Func <ExtractedFile, bool> filter, Action <Stream, ExtractedFile> extract) { long mlt = this.IsGameCube ? 1L : 4L; long srcPos = 0; List <FstFile> files = new List <FstFile>(); MemorySection bootbin = (this.IsGameCube || this.NStream.IsNkit) ? hdr: MemorySection.Read(inStream, 0x440); files.Add(new FstFile(null) { Name = "boot.bin", PartitionId = id, DataOffset = srcPos, Offset = srcPos, Length = (int)bootbin.Size, IsNonFstFile = true, OffsetInFstFile = 0 }); srcPos += bootbin.Size; MemorySection bi2bin = MemorySection.Read(inStream, 0x2000); files.Add(new FstFile(null) { Name = "bi2.bin", PartitionId = id, DataOffset = srcPos, Offset = srcPos, Length = (int)bi2bin.Size, IsNonFstFile = true, OffsetInFstFile = 0 }); srcPos += bi2bin.Size; //########### APPLOADER (appldr.bin) 0x2440 - Action Reply can have 0 as the main.dol MemorySection appldr = MemorySection.Read(inStream, Math.Min(bootbin.ReadUInt32B(0x420) == 0 ? uint.MaxValue : (bootbin.ReadUInt32B(0x420) * mlt), (bootbin.ReadUInt32B(0x424) * mlt)) - srcPos); files.Add(new FstFile(null) { Name = "appldr.bin", PartitionId = id, DataOffset = srcPos, Offset = srcPos, Length = 0x20 + appldr.ReadUInt32B(0x14) + appldr.ReadUInt32B(0x18), IsNonFstFile = true, OffsetInFstFile = 0 }); srcPos += appldr.Size; //########### APP (main.dol) MemorySection maindol = null; if (bootbin.ReadUInt32B(0x420) < bootbin.ReadUInt32B(0x424)) { maindol = MemorySection.Read(inStream, (bootbin.ReadUInt32B(0x424) * mlt) - srcPos); uint maindolSize = 0; for (int i = 0; i < 18; i++) { if (maindol.ReadUInt32B(0x0 + (i * 4)) != 0) //7 text offsets, 11 data offsets { maindolSize = Math.Max(maindolSize, maindol.ReadUInt32B(0x0 + (i * 4)) + maindol.ReadUInt32B(0x90 + (i * 4))); } } files.Add(new FstFile(null) { Name = "main.dol", PartitionId = id, DataOffset = srcPos, Offset = srcPos, Length = maindolSize, IsNonFstFile = true, OffsetInFstFile = 0 }); srcPos += maindol.Size; } MemorySection fstbin = MemorySection.Read(inStream, bootbin.ReadUInt32B(0x428) * mlt); files.Add(new FstFile(null) { Name = "fst.bin", PartitionId = id, DataOffset = srcPos, Offset = srcPos, Length = (int)fstbin.Size, IsNonFstFile = true, OffsetInFstFile = 0 }); srcPos += fstbin.Size; List <FstFile> fstFiles = FileSystem.Parse(fstbin, null, id, this.IsGameCube)?.Files?.OrderBy(a => a.Offset)?.ThenBy(a => a.Length)?.ToList(); if (fstFiles == null) { throw new HandledException(string.Format("FST Corrupt or misaligned, could not be parsed at position 0x{0}", (bootbin.ReadUInt32B(0x424) * mlt).ToString("X8"))); } files.AddRange(fstFiles); Dictionary <string, MemorySection> mem = new Dictionary <string, MemorySection>(); mem.Add("boot.bin", bootbin); mem.Add("bi2.bin", bi2bin); mem.Add("appldr.bin", appldr); mem.Add("main.dol", maindol); mem.Add("fst.bin", fstbin); List <ExtractedFile> exfiles = files.OrderBy(a => a.Offset).ThenBy(a => a.Length).Select(a => new ExtractedFile(this.IsGameCube ? DiscType.GameCube : DiscType.Wii, this.NStream.Id8, this.IsGameCube ? null : id, a.DataOffset, a.Length, a.Path, a.Name, mem.ContainsKey(a.Name) ? ExtractedFileType.System : ExtractedFileType.File)).Where(a => filter(a)).ToList(); if (files == null || files.Count == 0) { return(createExtractResult((Region)bi2bin.ReadUInt32B(0x18), null)); } foreach (ExtractedFile f in exfiles) //read the files and write them out as goodFiles (possible order difference) { if (srcPos < f.Offset) { inStream.Copy(Stream.Null, f.Offset - srcPos); srcPos += f.Offset - srcPos; } if (f.Type == ExtractedFileType.System) { using (MemoryStream ms = new MemoryStream(mem[f.Name].Data)) extract(ms, f); } else { extract(inStream, f); srcPos += f.Length; } } return(createExtractResult((Region)bi2bin.Read8(0x18), null)); }
private long partitionStreamWrite(LongRef outSize, Stream inStream, Stream target, long size, DatData settingsData, NkitPartitionPatchInfo patchInfo, WiiHashStore hashes, Coordinator pc) { DatData data = settingsData; List <string> addedFiles = new List <string>(); DateTime dt = DateTime.Now; MemorySection hdr = MemorySection.Read(inStream, 0x440); long srcPos = hdr.Size; long outPos = 0; long imageSize = 0; try { if (hdr.ReadString(0, 4) == "\0\0\0\0") { long nullsPos = 0; long fileLength = -1; LongRef gapLength = new LongRef() { Value = -1 }; target.Write(hdr.Data, 0, (int)hdr.Size); MemorySection sz = MemorySection.Read(inStream, 4); srcPos += 4; outPos += hdr.Size; imageSize = sz.ReadUInt32B(0) * 4L; outSize.Value = NStream.HashedLenToData(imageSize); JunkStream junk = new JunkStream(hdr.Read(0, 4), hdr.Read8(6), outSize.Value); //SET LENGTH FROM HEADER outPos += writeGap(ref fileLength, gapLength, ref nullsPos, ref srcPos, outPos, inStream, target, junk, true, patchInfo.ScrubManager); } else { string idVer = hdr.ReadString(0x200, 8); if (idVer != "NKIT v01") { throw new Exception(string.Format("{0} not supported by this version", idVer)); } bool isNkit = idVer.StartsWith("NKIT"); imageSize = NStream.HashedLenToData((hdr.ReadUInt32B(0x210) * 4L)); outSize.Value = imageSize; string junkId = hdr.ReadString(0x214, 4); JunkStream junk = new JunkStream(hdr.Read(0, 4), hdr.Read8(6), imageSize); //SET LENGTH FROM HEADER MemorySection fst; long mainDolAddr = hdr.ReadUInt32B(0x420); //############################################################################ //# READ DISC START MemorySection hdrToFst = MemorySection.Read(inStream, (hdr.ReadUInt32B(0x424) * 4L) - hdr.Size); srcPos += hdrToFst.Size; fst = MemorySection.Read(inStream, hdr.ReadUInt32B(0x428) * 4L); long postFstPos = (hdr.ReadUInt32B(0x424) * 4L) + fst.Size; srcPos += fst.Size; hashes.WriteFlagsData(imageSize, inStream); srcPos += hashes.FlagsLength; patchInfo.PartitionDataHeader = hdr; patchInfo.Fst = fst; //############################################################################ //# WRITE DISC START target.Write(hdr.Data, 0, (int)hdr.Size); target.Write(hdrToFst.Data, 0, (int)hdrToFst.Size); //padded when read target.Write(fst.Data, 0, fst.Data.Length); hdrToFst = null; //let this be collected if needed outPos = (hdr.ReadUInt32B(0x424) * 4L) + fst.Size; long nullsPos = outPos + 0x1c; string error; List <ConvertFile> conFiles = NkitFormat.GetConvertFstFiles(inStream, size, hdr, fst, false, -1, out error); if (conFiles == null) { if (error != null) { _log?.LogDetail(error); } ConvertFile cf = new ConvertFile(imageSize - srcPos, true) //result.ImageInfo.IsoSize { FstFile = new FstFile(null) { DataOffset = hdr.ReadUInt32B(0x424), Offset = hdr.ReadUInt32B(0x424), Length = (int)fst.Size }, }; outPos += writeGap(cf, ref nullsPos, ref srcPos, outPos, inStream, target, junk, true, patchInfo.ScrubManager); } else { conFiles[0].GapLength -= hashes.FlagsLength; //fix for a few customs (no gap between the fst and the first file on the source image, but the hash mask makes it look like there is) //########### FILES bool firstFile = true; for (int i = 0; i < conFiles.Count; i++) //read the files and write them out as goodFiles (possible order difference { ConvertFile f = conFiles[i]; FstFile ff = f.FstFile; if (!firstFile) //fst already written { //Debug.WriteLine(string.Format(@"{0}>{1} : {2}>{3} : {4} : {5}/{6}", ff.DataOffset.ToString("X8"), outPos.ToString("X8"), (ff.DataOffset + ff.Length).ToString("X8"), (outPos + ff.Length).ToString("X8"), ff.Length.ToString("X8"), ff.Path, ff.Name)); if (srcPos < ff.DataOffset) //skip any padding (not written for wii currently) { inStream.Copy(ByteStream.Zeros, ff.DataOffset - srcPos); //skip any 32k align padding etc srcPos += ff.DataOffset - srcPos; } //write file if (ff.DataOffset == mainDolAddr) { hdr.WriteUInt32B(0x420, (uint)(outPos / 4L)); } fst.WriteUInt32B(ff.OffsetInFstFile, (uint)(outPos / 4L)); outPos += copyFile(f, ref nullsPos, ref srcPos, outPos, inStream, target); } if (outPos < imageSize) { long gapLen = writeGap(f, ref nullsPos, ref srcPos, outPos, inStream, target, junk, i == 0 || i == conFiles.Count - 1, patchInfo.ScrubManager); outPos += gapLen; if (!firstFile) { fst.WriteUInt32B(ff.OffsetInFstFile + 4, (uint)(ff.Length)); } } firstFile = false; } } } return(srcPos); } catch (Exception ex) { throw pc.SetReaderException(ex, "NkitReaderWii.Read - partitionRead"); } }