private void AnalyzeStructure(BinaryReader reader, uint baseOffset, uint size, TagLayoutGuess result) { var lookBehind = new uint[4]; TagFixup potentialGuess = null; for (uint offset = 0; offset < size; offset += 4) { var val = reader.ReadUInt32(); TagFixup fixup; if (_resourceFixupsByWriteOffset.TryGetValue(baseOffset + offset, out fixup)) { // Value is a resource reference result.Add(offset, new ResourceReferenceGuess()); } else if (_dataFixupsByWriteOffset.TryGetValue(baseOffset + offset, out fixup)) { // Value is a pointer if (offset >= 0x4) { // Tag block or data reference - need another padding value to confirm it potentialGuess = fixup; } } else if (offset >= 0xC && lookBehind[0] == 0 && lookBehind[1] == 0 && _cache.ContainsClass(new MagicNumber((int)lookBehind[2]))) { // Tag reference if (val != 0xFFFFFFFF && val < _cache.Tags.Count) { var referencedTag = _cache.Tags[(int)val]; if (referencedTag != null && referencedTag.Class.Value == (int)lookBehind[2]) { result.Add(offset - 0xC, new TagReferenceGuess()); } } } else if (val == 0 && potentialGuess != null) { // Found a potential padding value - check if we can confirm the potential guess's type if (lookBehind[1] != 0) { // Tag block - seek to it and analyze it reader.BaseStream.Position = potentialGuess.TargetOffset; var elementLayout = AnalyzeStructure(reader, lookBehind[1]); reader.BaseStream.Position = baseOffset + offset + 4; result.Add(offset - 0x8, new TagBlockGuess(elementLayout)); } else if (offset >= 0x10 && lookBehind[1] == 0 && lookBehind[2] == 0 && lookBehind[3] != 0) { // Data reference result.Add(offset - 0x10, new DataReferenceGuess()); } potentialGuess = null; } else { // Tag block and data reference guesses must be followed by padding potentialGuess = null; } for (var i = 3; i > 0; i--) { lookBehind[i] = lookBehind[i - 1]; } lookBehind[0] = val; } }