public long Encode(Stream s, ref long srcPos, long nulls, long gapLength, JunkStream junk, ScrubManager scrub, Stream output, ILog log) { int read = 0; long written = 0; _headerWritten = false; junk.Position = srcPos; if (gapLength != 0) { int[] results = new int[0x400]; byte[] scrubBytes = new byte[results.Length]; byte[] buff = new byte[Math.Min(gapLength, Gap.BlockSize * results.Length)]; byte[] jbuff = new byte[buff.Length]; //cache some junk up front so we can thread the block comparisons long start = srcPos; do { int req = (int)Math.Min(buff.Length, gapLength - this.Length); Task.WaitAll( Task.Run(() => read = s.Read(buff, 0, req)), Task.Run(() => junk.Read(jbuff, 0, req)) ); int blocks = (int)(read / Gap.BlockSize) + (int)Math.Min(1, read % Gap.BlockSize); long pos = srcPos; Parallel.For(0, blocks, bb => { byte?scrubByte; if ((results[bb] = blockCompare(nulls, jbuff, junk.JunkLength, scrub, buff, (int)Gap.BlockSize * bb, (int)Math.Min(Gap.BlockSize * (bb + 1), read), pos, start == pos, out scrubByte)) == 1) { scrubBytes[bb] = scrubByte.Value; } }); for (int bb = 0; bb < blocks; bb++) { if (results[bb] == 0) { this.Set(); //junk } else if (results[bb] == 1) { this.Set(scrubBytes[bb]); //scrubbed //log?.LogDebug(string.Format(">>> Scrubbed Written: {0} : {1}", srcPos.ToString("X8"), bb.ToString())); } else { //log?.LogDebug(string.Format(">>> NonJunk Written: {0} : {1}", srcPos.ToString("X8"), bb.ToString())); written += this.Set(buff, (int)Gap.BlockSize * bb, (int)Math.Min(Gap.BlockSize * (bb + 1), read), output); //preserve (also data that's part scrubbed part junk in a 256 byte block) } } srcPos += read; }while (this.Length < gapLength && read != 0); //sum of processed gap blocks < exact gap } written += write(output, !_headerWritten); return(written); }
public void Populate(byte[] data, long discOffset, long size) { base.DiscOffset = discOffset; base.Size = size; if (_junk != null) { _junk.Read(_junkData, 0, (int)base.Size); } base.Data = _useBuff ? data : _junkData; }
internal WiiFillerSectionItem(NStream stream, long discOffset, byte[] data, long size, bool useBuff, JunkStream junk) : base(stream, discOffset, data, size) { _useBuff = useBuff; _junk = junk; if (_junk != null) { _junk.Position = discOffset; _junkData = new byte[this.Data.Length]; _junk.Read(_junkData, 0, (int)base.Size); Array.Clear(_junkData, 0, 28); base.Data = _useBuff ? data : _junkData; } }
public bool Unscrub(List <JunkRedumpPatch> junkPatches) { bool changed = false; //bool performCheck = true; //start on the assumption last was valid as it would be hassle to work out List <FstFile> nulls = new List <FstFile>(); bool good = _data.IsValid(false); //forces decrypt and hash cache build and test - does not test data in blocks matchs H0 table Parallel.For(0, _data.UsedBlocks, bi => _unscrubValid[bi] = _data.BlockIsValid(bi)); //test data matches H0 table for (int bi = 0; bi < _data.UsedBlocks; bi++) { if (!_unscrubValid[bi]) { if (_junk == null) { _junk = new JunkStream(_partHdr.Id, _partHdr.DiscNo, _partHdr.PartitionDataSize); } _junk.Position = NStream.OffsetToData(this.Offset + _data.BlockDataOffset(bi), true); _junk.Read(_data.Decrypted, _data.BlockDataOffset(bi), 0x7c00); _data.MarkBlockUnscrubbedAndDirty(bi); changed = true; } } if (junkPatches != null && junkPatches.Count != 0) { foreach (JunkRedumpPatch jp in junkPatches) { if (jp.Offset >= this.DiscOffset && jp.Offset < this.DiscOffset + this.Size) { Array.Copy(jp.Data, 0, _data.Decrypted, jp.Offset - this.DiscOffset, jp.Data.Length); _data.MarkBlockDirty((int)((jp.Offset - this.DiscOffset) / 0x8000)); //560de532 } } } if (changed) { good = _data.IsValid(true); //true as changes were made if (!good) { bool zerod = false; List <Tuple <long, int, FstFile> > h3Nulls = new List <Tuple <long, int, FstFile> >(_partHdr.ScrubManager.H3Nulls); if (h3Nulls.Count != 0) { int dataLen = (int)NStream.HashedLenToData(this.Decrypted.Length); foreach (Tuple <long, int, FstFile> n in h3Nulls) { if (n.Item1 >= this.DataOffset && n.Item1 < this.DataOffset + dataLen) { int idx = (int)((n.Item1 - this.DataOffset) / 0x7c00); _data.MarkBlockDirty(idx); int pos = (int)NStream.DataToOffset(n.Item1 - this.DataOffset, true); Array.Clear(_data.Decrypted, pos, n.Item2); zerod = true; } } } if (zerod) { good = _data.IsValid(true); } if (!good) { this.H3Errors++; } } } return(changed); }