public static FileSystem Parse(Stream fstData, long fstOffset, long length, string id, bool isGc) { MemorySection ms = MemorySection.Read(fstData, length); FstFile ff = new FstFile(null) { Name = "fst.bin", DataOffset = fstOffset, Offset = NStream.DataToOffset(fstOffset, !isGc), IsNonFstFile = true, Length = (int)fstData.Length }; return(Parse(ms, ff, id, isGc)); }
private static uint recurseFst(MemorySection ms, FstFolder folder, long names, uint i, string id, bool isGc) { uint j; uint hdr = ms.ReadUInt32B((int)(12 * i)); long name = names + hdr & 0x00ffffffL; int type = (int)(hdr >> 24); string nm = ms.ReadStringToNull((int)name, Encoding.GetEncoding("shift-jis")); uint size = ms.ReadUInt32B((int)(12 * i + 8)); if (type == 1) { FstFolder f = i == 0 ? folder : new FstFolder(folder) { Name = nm }; if (i != 0) { folder.Folders.Add(f); } for (j = i + 1; j < size;) { j = recurseFst(ms, f, names, j, id, isGc); } return(size); } else { int pos = (int)(12 * i + 4); long doff = ms.ReadUInt32B(pos) * (isGc ? 1L : 4L); //offset in data size = ms.ReadUInt32B((int)(12 * i + 8)); long off = NStream.DataToOffset(doff, !isGc); //offset in raw partition folder.Files.Add(new FstFile(folder) { DataOffset = doff, Offset = off, Length = size, Name = nm, PartitionId = id, OffsetInFstFile = pos }); return(i + 1); } }
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); }