internal static long ProcessGap(ref long nullsPos, ConvertFile file, ref long srcPos, Stream s, JunkStream junk, bool firstOrLastFile, ScrubManager scrub, Stream output, ILog log) { long nulls = 0; if (file.GapLength != 0) { if (srcPos % 4 != 0) { throw new Exception("Src Position should be on a 4 byte boundary"); } long size = file.GapLength; long start = srcPos; long maxNulls = Math.Max(0, nullsPos - srcPos); //0x1cL //maxNulls = 0x1c; if (size < maxNulls) //need to test this commented if { nulls = size; } else { nulls = size >= 0x40000 && !firstOrLastFile ? 0 : maxNulls; } } //might need to still call if we have a junk file return(file.Gap.Encode(s, ref srcPos, nulls, file.GapLength, junk, scrub, output, log)); }
private long copyFile(ConvertFile file, ref long nullsPos, ref long srcPos, long dstPos, Stream inStream, Stream target) { FstFile ff = file.FstFile; long size = ff.Length; if (size == 0) { return(0); //could be legit or junk } size += size % 4 == 0 ? 0 : 4 - (size % 4); try { inStream.Copy(target, size); } catch (Exception ex) { throw new HandledException(ex, "Copy file '{0}' failed at Data Position {1} ({2} bytes)", ff.Name, ff.DataOffset.ToString("X"), ff.Length.ToString()); } srcPos += size; dstPos += size; nullsPos = dstPos + 0x1CL; return(size); }
private long writeGap(ConvertFile file, ref long nullsPos, ref long srcPos, long dstPos, Stream inStream, Stream target, JunkStream junk, bool firstOrLastFile, ScrubManager scrub) { long fileLength = file.FstFile.Length; LongRef gapLength = new LongRef() { Value = file.GapLength }; dstPos = writeGap(ref fileLength, gapLength, ref nullsPos, ref srcPos, dstPos, inStream, target, junk, firstOrLastFile, scrub); file.FstFile.Length = fileLength; file.GapLength = gapLength.Value; return(dstPos); }
private long copyFile(ConvertFile file, ref long nullsPos, ref long srcPos, long dstPos, long imageSize, Stream inStream, Stream target) { FstFile ff = file.FstFile; long size = ff.Length; if (size == 0) { return(0); //could be legit or junk } size += size % 4 == 0 ? 0 : 4 - (size % 4); size = Math.Min(size, imageSize - dstPos); //never overwrite file length (starfox e3 fix) inStream.Copy(target, size); srcPos += size; dstPos += size; nullsPos = dstPos + 0x1CL; return(size); }
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"); } }
internal static long CopyFile(ref long nullsPos, ConvertFile conFile, FstFile prevFile, Stream dest, ref long srcPos, long dstPos, Stream srcStream, JunkStream junkNStream, long imageSize, out bool missing) { //long pos = dest.Position; missing = false; FstFile file = conFile.FstFile; long size = file.Length + (file.Length % 4 == 0 ? 0 : (4 - (file.Length % 4))); if (srcPos + size > imageSize) { size = file.Length; //some rare GC demos end at the end of a non aligned file. This fixes it - v1.2 bugfix } long written = size; byte[] f = new byte[Math.Min(0x30, size)]; srcStream.Read(f, 0, f.Length); //then read while junk is created if (prevFile != null && prevFile.DataOffset == file.DataOffset && prevFile.Length == 0) //null file overlapped this file so set nullsPos to have a gap (XGIII) needs fst sorting by offset then size { nullsPos = srcPos + 0x1CL; //will already be aligned } int nulls = (int)(nullsPos - srcPos); int countNulls = 0; if (f.Length > nulls) { junkNStream.Position = file.DataOffset; //async junk gen for (int i = 0; i < f.Length && f[i] == 0; i++) { countNulls++; } if (countNulls < f.Length) //don't test all nulls { missing = junkNStream.Compare(f, 0, f.Length, Math.Max(0, countNulls)) == f.Length; } } if (missing) //start of file is junk { //check the remainder of the file MemorySection junkFile = MemorySection.Read(srcStream, size - f.Length); missing = junkNStream.Compare(junkFile.Data, 0, (int)junkFile.Size, 0) == junkFile.Size; if (missing) { written = 0; conFile.Gap.SetJunkFile((uint)conFile.FstFile.Length, countNulls); } else //not 100% junk, write the file out { dest.Write(f, 0, f.Length); dest.Write(junkFile.Data, 0, (int)junkFile.Size); } junkFile = null; } else { dest.Write(f, 0, f.Length); srcStream.Copy(dest, size - f.Length); //copy file } if (!missing) //reset the gap when no junk { nullsPos = srcPos + size + 0x1c; if (nullsPos % 4 != 0) { nullsPos += 4 - (nullsPos % 4); } } srcPos += size; return(written); }
internal static void NkitWriteFileSystem(Context ctx, NkitInfo imageInfo, long mlt, Stream inStream, ref long srcPos, ref long dstPos, MemorySection hdr, MemorySection fst, ref long mainDolAddr, Stream target, long nullsPos, JunkStream js, List <ConvertFile> conFiles, out List <ConvertFile> missingFiles, ScrubManager scrub, long imageSize, ILog log) { FstFile ff; //########### FILES bool firstFile = true; ConvertFile lastf = conFiles.Last(); ConvertFile prevf = null; missingFiles = new List <ConvertFile>(); foreach (ConvertFile f in conFiles) //read the files and write them out as goodFiles (possible order difference { ff = f.FstFile; if (!firstFile) { if (srcPos == mainDolAddr && mainDolAddr == (hdr.ReadUInt32B(0x420) * mlt)) { mainDolAddr = dstPos; //main/default.dol is moving } //Debug.WriteLine(string.Format(@"{5} : {0} : {1} : {2} : {3}/{4}", ff.DataOffset.ToString("X8"), (ff.DataOffset + ff.Length).ToString("X8"), /*(nextFile.DataOffset - lastEnd).ToString("X8"),*/ ff.Length.ToString("X8"), ff.Path, ff.Name, ff.OffsetInFstFile.ToString("X8"))); //srcPos aligned at 32k and the length is 32k (audio file) ensure new dest is also aligned if (f.Alignment == 0 || (f.Alignment != -1 && dstPos % f.Alignment != 0)) //XGIII audio in race, Zelda collection games for TGC { long pad; if (f.Alignment == 0) //no shrinking { pad = Math.Max(0, ff.DataOffset - dstPos); } else //align { pad = (int)(dstPos % f.Alignment == 0 ? 0 : f.Alignment - (dstPos % f.Alignment)); } imageInfo.FilesAligned += 1; ByteStream.Zeros.Copy(target, pad); imageInfo.BytesPreservationDiscPadding += pad; dstPos += pad; } fst.WriteUInt32B(ff.OffsetInFstFile, (uint)(dstPos / mlt)); //replace copy with junk test - adjust fst length to %4 long l = srcPos; imageInfo.FilesTotal += 1; long written = NkitFormat.CopyFile(ref nullsPos, f, prevf?.FstFile, target, ref srcPos, dstPos, inStream, js, imageSize, out bool missing); if (missing) { missingFiles.Add(f); } dstPos += written; imageInfo.BytesData += srcPos - l; //read if (f.Gap.JunkFile != 0) //encode the gap and write - pad to %4 { imageInfo.BytesJunkFiles += f.Gap.JunkFile + (f.Gap.JunkFile % 4 == 0 ? 0 : (4 - (f.Gap.JunkFile % 4))); fst.WriteUInt32B(ff.OffsetInFstFile + 4, 0); //modify size to be remainder of 4 } } if (f.GapLength != 0 || f.Gap.JunkFile != 0) { long l = NkitFormat.ProcessGap(ref nullsPos, f, ref srcPos, inStream, js, firstFile || f == lastf, scrub, target, log); imageInfo.BytesGaps += f.GapLength; imageInfo.BytesPreservationData += l; dstPos += l; } firstFile = false; prevf = f; } }
public void Read(Context ctx, NStream inStream, Stream outStream, Coordinator pc) { try { DatData data = ctx.Dats; List <string> addedFiles = new List <string>(); DateTime dt = DateTime.Now; MemorySection hdr = inStream.DiscHeader; 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"); uint nkitCrc = hdr.ReadUInt32B(0x208); uint imageSize = hdr.ReadUInt32B(0x210); string junkId = hdr.ReadString(0x214, 4); if (junkId != "\0\0\0\0") { inStream.ChangeJunk(junkId); } hdr.WriteUInt32B(0x200, 0); hdr.WriteUInt32B(0x204, 0); hdr.WriteUInt32B(0x208, 0); hdr.WriteUInt32B(0x20C, 0); hdr.WriteUInt32B(0x210, 0); hdr.WriteUInt32B(0x214, 0); hdr.WriteUInt32B(0x218, 0); MemorySection fst; long mainDolAddr = hdr.ReadUInt32B(0x420); NCrc crc = new NCrc(); NStream target = new NStream(new CryptoStream(outStream, crc, CryptoStreamMode.Write)); //############################################################################ //# READ DISC START MemorySection hdrToFst = MemorySection.Read(inStream, hdr.ReadUInt32B(0x424) - hdr.Size); fst = MemorySection.Read(inStream, hdr.ReadUInt32B(0x428) + (hdr.ReadUInt32B(0x428) % 4 == 0 ? 0 : 4 - (hdr.ReadUInt32B(0x428) % 4))); long srcPos = hdr.ReadUInt32B(0x424) + fst.Size; //############################################################################ //# WRITE DISC START target.Write(hdr.Data, 0, (int)hdr.Size); pc.ReaderCheckPoint1PreWrite(junkId, hdr.ReadUInt32B(0x208)); //size that we will output from this read crc.Snapshot("hdr.bin"); target.Write(hdrToFst.Data, 0, (int)hdrToFst.Size); //padded when read crc.Snapshot("bi2.bin, appldr.bin, main.dol"); target.Write(fst.Data, 0, fst.Data.Length); crc.Snapshot("fst.bin"); hdrToFst = null; //let this be collected if needed long dstPos = hdr.ReadUInt32B(0x424) + fst.Size; long nullsPos = dstPos + 0x1c; string error; List <ConvertFile> conFiles = NkitFormat.GetConvertFstFiles(inStream, inStream.Length, hdr, fst, true, -1, out error); //result.ImageInfo.IsoSize if (conFiles == null) { if (error != null) { _log?.LogDetail(error); } ConvertFile cf = new ConvertFile(inStream.Length - srcPos, true) //result.ImageInfo.IsoSize { FstFile = new FstFile(null) { DataOffset = hdr.ReadUInt32B(0x424), Offset = hdr.ReadUInt32B(0x424), Length = (int)fst.Size }, }; dstPos += writeGap(cf, ref nullsPos, ref srcPos, dstPos, inStream, target, true); } else { //########### 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"), dstPos.ToString("X8"), (ff.DataOffset + ff.Length).ToString("X8"), (dstPos + ff.Length).ToString("X8"), ff.Length.ToString("X8"), ff.Path, ff.Name)); if (srcPos < ff.DataOffset) { 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)dstPos); } fst.WriteUInt32B(ff.OffsetInFstFile, (uint)dstPos); dstPos += copyFile(f, ref nullsPos, ref srcPos, dstPos, imageSize, inStream, target); } if (dstPos < imageSize) { dstPos += writeGap(f, ref nullsPos, ref srcPos, dstPos, inStream, target, i == 0 || i == conFiles.Count - 1); if (!firstFile) { fst.WriteUInt32B(ff.OffsetInFstFile + 4, (uint)ff.Length); } } firstFile = false; } } crc.Snapshot("files"); 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; if (imageSize != dstPos) { throw pc.SetReaderException(new HandledException("Nkit image read output {0} bytes not the expected {1}!", dstPos.ToString(), imageSize.ToString())); } pc.ReaderCheckPoint2Complete(crc, false, nkitCrc, crc.FullCrc(true), this.VerifyIsWrite, hdr.Data, nkitCrc == crc.FullCrc(true) ? "NKit Valid" : "NKit Invalid"); pc.ReaderCheckPoint3Complete(); } catch (Exception ex) { throw pc.SetReaderException(ex, "NkitReaderGc.Read - Read and convert"); //don't let the writer lock } }
private long writeGap(ConvertFile file, ref long nullsPos, ref long srcPos, long dstPos, NStream inStream, Stream target, bool firstOrLastFile) { if (file.GapLength == 0) { if (file.FstFile.Length == 0) { nullsPos = dstPos + 0x1c; } return(0); } MemorySection ms = MemorySection.Read(inStream, 4); srcPos += 4; long size = ms.ReadUInt32B(0); GapType gt = (GapType)(size & 0b11); size &= 0xFFFFFFFC; if (size == 0xFFFFFFFC) //for wii only. not a thing for GC { srcPos += 4; inStream.Read(ms.Data, 0, 4); size = 0xFFFFFFFCL + (long)ms.ReadUInt32B(0); //cater for files > 0xFFFFFFFF } long nulls; long junkFileLen = 0; //set nullsPos value if zerobyte file without junk if (gt == GapType.JunkFile) { nullsPos = Math.Min(nullsPos - dstPos, 0); nulls = (size & 0xFC) >> 2; inStream.Read(ms.Data, 0, 4); srcPos += 4; junkFileLen = ms.ReadUInt32B(0); file.FstFile.Length = junkFileLen; junkFileLen += junkFileLen % 4 == 0 ? 0 : 4 - (junkFileLen % 4); ByteStream.Zeros.Copy(target, nulls); inStream.JunkStream.Position = dstPos + nulls; inStream.JunkStream.Copy(target, junkFileLen - nulls); dstPos += junkFileLen; if (file.GapLength <= 8) { return(junkFileLen); } else { //read gap inStream.Read(ms.Data, 0, 4); srcPos += 4; size = ms.ReadUInt32B(0); gt = (GapType)(size & 0b11); size &= 0xFFFFFFFC; } } else if (file.FstFile.Length == 0) //last zero byte file was legit { nullsPos = dstPos + 0x1c; } long maxNulls = Math.Max(0, nullsPos - dstPos); //0x1cL if (size < maxNulls) //need to test this commented if { nulls = size; } else { nulls = size >= 0x40000 && !firstOrLastFile ? 0 : maxNulls; } if (gt == GapType.AllJunk) { ByteStream.Zeros.Copy(target, nulls); inStream.JunkStream.Position = dstPos + nulls; inStream.JunkStream.Copy(target, size - nulls); dstPos += size; } else if (gt == GapType.AllScrubbed) { ByteStream.Zeros.Copy(target, size); dstPos += size; } else { long prg = size; byte btByte = 0x00; GapBlockType bt = GapBlockType.Junk; //should never be used while (prg > 0) { inStream.Read(ms.Data, 0, 4); srcPos += 4; long bytes; long blk = ms.ReadUInt32B(0); GapBlockType btType = (GapBlockType)(blk >> 30); bool btRepeat = btType == GapBlockType.Repeat; if (!btRepeat) { bt = btType; } long cnt = 0x3FFFFFFF & blk; if (bt == GapBlockType.NonJunk) { bytes = Math.Min(cnt * Gap.BlockSize, prg); inStream.Copy(target, bytes); srcPos += bytes; } else if (bt == GapBlockType.ByteFill) { if (!btRepeat) { btByte = (byte)(0xFF & cnt); //last 8 bits when not repeating are the byte cnt >>= 8; } bytes = Math.Min(cnt * Gap.BlockSize, prg); Stream bs; switch (btByte) { case 0x00: bs = ByteStream.Zeros; break; case 0x55: bs = ByteStream.Fives; break; case 0xff: bs = ByteStream.FFs; break; default: bs = new ByteStream(btByte); break; } bs.Copy(target, bytes); } else //if (bt == GapBlockType.Junk) { bytes = Math.Min(cnt * Gap.BlockSize, prg); maxNulls = Math.Max(0, nullsPos - dstPos); //0x1cL if (prg < maxNulls) { nulls = bytes; } else { nulls = bytes >= 0x40000 && !firstOrLastFile ? 0 : maxNulls; } ByteStream.Zeros.Copy(target, nulls); inStream.JunkStream.Position = dstPos + nulls; inStream.JunkStream.Copy(target, bytes - nulls); } prg -= bytes; dstPos += bytes; } } return(size + junkFileLen); }
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"); } }