private void AnalyzeStructure(BinaryReader reader, uint baseOffset, uint size, TagLayoutGuess result)
{
var lookBehind = new uint[4];
TagPointerFixup potentialGuess = null;
for (uint offset = 0; offset < size; offset += 4)
{
var val = reader.ReadUInt32();
TagPointerFixup fixup;
if (_resourceFixupsByWriteOffset.Contains(baseOffset + offset))
{
// 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 && _tagGroups.Contains(new Tag((int)lookBehind[2])))
{
// Tag reference
if (val != 0xFFFFFFFF && val < _cache.Tags.Count)
{
var referencedTag = _cache.Tags[(int)val];
if (referencedTag != null && referencedTag.Group.Tag.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, CalculateAlignment(lookBehind[0])));
}
else if (offset >= 0x10 && lookBehind[1] == 0 && lookBehind[2] == 0 && lookBehind[3] != 0)
{
// Data reference
result.Add(offset - 0x10, new DataReferenceGuess(CalculateAlignment(lookBehind[0])));
}
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;
}
}