private void patchGroups(NkitPartitionPatchInfo patchInfo, WiiDiscHeaderSection discHeader, long crcPatchOffset, byte[] crcPatchData) { long partDataOffset = patchInfo.DiscOffset + patchInfo.PartitionHeader.Size; int groupIdx = (int)((crcPatchOffset - partDataOffset) / WiiPartitionSection.GroupSize); byte[] data = new byte[WiiPartitionSection.GroupSize]; WiiPartitionHeaderSection wh = new WiiPartitionHeaderSection(discHeader, null, partDataOffset, patchInfo.PartitionHeader.Data, patchInfo.PartitionHeader.Size) { ScrubManager = patchInfo.ScrubManager }; wh.Initialise(true, patchInfo.PartitionDataHeader.ReadString(0, 4)); #if DECRYPT WiiPartitionGroupSection wp = new WiiPartitionGroupSection(discHeader, wh, ph.Data, , ph.Data.Length, false); #else WiiPartitionGroupSection wp = new WiiPartitionGroupSection(discHeader, wh, data, partDataOffset, Math.Min(WiiPartitionSection.GroupSize, crcPatchData.Length), true); #endif if (patchInfo.Fst != null) { using (MemoryStream fstStream = new MemoryStream(patchInfo.Fst.Data)) { fstPatch(patchInfo, wp, crcPatchOffset, crcPatchData, fstStream); } } MemorySection d = new MemorySection(crcPatchData); for (long i = 0; i < crcPatchData.Length; i += WiiPartitionSection.GroupSize) { Array.Copy(d.Data, (int)i, data, 0, Math.Min(WiiPartitionSection.GroupSize, d.Size - i)); wp.Populate(groupIdx++, data, crcPatchOffset + i, Math.Min(WiiPartitionSection.GroupSize, d.Size - i)); wp.ForceHashes(null); if (patchInfo.HashGroups.ContainsKey(wp.DiscOffset)) { hashPatchGroup(patchInfo, wp); d.Write((int)i, wp.Encrypted, (int)wp.Size); } } }
private void fstPatch(NkitPartitionPatchInfo pi, WiiPartitionGroupSection wp, long patchOffset, byte[] crcPatchData, Stream fst) { long fstOffset = pi.PartitionDataHeader.ReadUInt32B(0x424) * 4L; long length = pi.Fst.Data.Length; //seek to fst group int baseGroupIdx = (int)((patchOffset - (pi.DiscOffset + wp.Header.Size)) / WiiPartitionSection.GroupSize); int gs = (int)(fstOffset / (0x7c00L * 64)); int ge = (int)((fstOffset + length) / (0x7c00L * 64)); if ((int)((fstOffset + length) % (0x7c00L * 64)) == 0) { ge--; //don't load the next group if the data will end on the last byte } if (gs > baseGroupIdx || ge < baseGroupIdx) { return; } using (MemoryStream dest = new MemoryStream(crcPatchData)) { if (gs != baseGroupIdx) { dest.Seek((gs - baseGroupIdx) * WiiPartitionSection.GroupSize, SeekOrigin.Current); } long dstOffset = NStream.DataToHashedLen(fstOffset) % WiiPartitionSection.GroupSize; //offset in hashed group long total = 0; for (int i = gs; i <= ge; i++) { long dataPos = 0x7c00 * 64 * i; int dataLen = (int)Math.Min(WiiPartitionSection.GroupSize, (wp.Header.ReadUInt32B(0x2bc) * 4L) - (WiiPartitionSection.GroupSize * i)); //can be less than 2mb if partition is small (or were are at the end) int read = dest.Read(wp.Data, 0, wp.Data.Length); if (read == 0) { break; } dest.Seek(-read, SeekOrigin.Current); wp.Populate(i, wp.Data, patchOffset, dataLen); //auto decrypted while (length != total && dstOffset != WiiPartitionSection.GroupSize) { dstOffset += 0x400; //skip hashes long l = fst.Read(wp.Decrypted, (int)dstOffset, (int)Math.Min(length - total, 0x8000 - (dstOffset % 0x8000))); //no padding etc as fst will be the same size dstOffset += l; total += l; } Array.Clear(wp.Decrypted, dataLen, (int)wp.Size - dataLen); int bnkCount = (int)(dataLen / 0x8000); int scrubbedCount = 0; for (int bi = 0; bi < bnkCount; bi++) { wp.MarkBlockDirty(bi); //set to force hash generation byte byt; if (pi.ScrubManager.IsBlockScrubbed(wp.Offset + (bi * 0x8000), out byt)) { wp.SetScrubbed(bi, byt); scrubbedCount++; } } repairBlocks(wp, scrubbedCount, bnkCount, true, false); #if DECRYPT dest.Write(wp.Decrypted, 0, dataLen); #else dest.Write(wp.Encrypted, 0, dataLen); #endif dstOffset = 0; } } }