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 int WriteRecoveryPartitionFiller(Stream crcStream, JunkStream junk, long pos, bool isUpdate, bool isNkit, WiiFillerSection fs, NStream target, string tmpFileName, ref string fileName, Crc crc, bool logAsDetail) { long nullBlocks = 0; //check for random junk - only on a handful of launch releases (Rampage, Ant Bully, Grim Adventures, Happy Feet etc) junk.Position = pos; long leadingNullsPos = pos; foreach (WiiFillerSectionItem fi in fs.Sections) { crcStream.Write(fi.Data, 0, (int)fi.Size); for (int i = 0; i < fi.Size; i += 0x8000) { int len = (int)Math.Min(0x8000L, fi.Size - (long)i); bool match = junk.Compare(fi.Data, i, len, junk.Position == leadingNullsPos ? 0x1c : 0) == len; if (match) { nullBlocks++; } else { if (nullBlocks != 0) { if (pos == leadingNullsPos) { ByteStream.Zeros.Copy(target, 0x1cL); junk.Position = pos + 0x1cL; junk.Copy(target, (nullBlocks * 0x8000L) - 0x1cL); } else { junk.Position = pos; junk.Copy(target, nullBlocks * 0x8000L); } pos += nullBlocks * 0x8000L; } nullBlocks = 0; target.Write(fi.Data, i, len); } } } target.Close(); crcStream.Close(); string fName = (fileName += crc.Value.ToString("X8")); bool redump; if (isUpdate) { redump = this.Settings.RedumpUpdateCrcs.Contains(crc.Value); } else { redump = this.Settings.RedumpChannels.FirstOrDefault(a => fName.StartsWith(a.Item1)) != null; } if (isNkit) { Directory.CreateDirectory(Settings.NkitRecoveryFilesPath); } return(storeRecoveryFile(redump, tmpFileName, fileName, Settings.RecoveryFilesPath, isNkit ? Settings.NkitRecoveryFilesPath : Settings.OtherRecoveryFilesPath, logAsDetail)); //rename the file, delete if dupe }