A guess at the layout of a tag.
 /// <summary>
 /// Makes a layout from a layout guess.
 /// </summary>
 /// <param name="layout">The layout guess.</param>
 /// <param name="name">The name of the final layout.</param>
 /// <param name="groupTag">The group tag of the final layout. Can be <c>null</c>.</param>
 /// <returns></returns>
 public static TagLayout MakeLayout(TagLayoutGuess layout, string name, Tag groupTag)
 {
     var result = new TagLayout(name, layout.Size, groupTag);
     var finalizer = new LayoutGuessFinalizer(result, 0);
     finalizer.ProcessLayout(layout);
     return result;
 }
Example #2
0
        public TagLayoutGuess AnalyzeStructure(BinaryReader reader, uint count)
        {
            if (count == 0)
            {
                throw new ArgumentException("count is 0", "count");
            }
            var startOffset = (uint)reader.BaseStream.Position;

            if (!_tagMap.IsBoundary(startOffset))
            {
                throw new InvalidOperationException("Cannot analyze a structure which does not start on a boundary");
            }
            var endOffset = _tagMap.GetNextBoundary(startOffset);

            if (startOffset == endOffset)
            {
                throw new InvalidOperationException("Structure is empty");
            }
            var offset      = startOffset;
            var elementSize = (endOffset - startOffset) / count;
            var result      = new TagLayoutGuess(elementSize);

            for (var i = 0; i < count; i++)
            {
                AnalyzeStructure(reader, offset, elementSize, result);
                offset += elementSize;
                reader.BaseStream.Position = offset;
            }
            return(result);
        }
Example #3
0
        private void ProcessLayout(TagLayoutGuess layout)
        {
            for (uint offset = 0; offset < layout.Size; offset += 4)
            {
                var guess = layout.TryGet(offset);
                if (guess != null)
                {
                    guess.Accept(offset, this);
                    offset += guess.Size - 4;
                }
                else
                {
                    var remaining = layout.Size - offset;
                    switch (remaining)
                    {
                    case 3:
                        _result.Add(MakeField(offset, BasicFieldType.Int16));
                        _result.Add(MakeField(offset, BasicFieldType.Int8));
                        break;

                    case 2:
                        _result.Add(MakeField(offset, BasicFieldType.Int16));
                        break;

                    case 1:
                        _result.Add(MakeField(offset, BasicFieldType.Int8));
                        break;

                    default:     // >= 4
                        _result.Add(MakeField(offset, BasicFieldType.Int32));
                        break;
                    }
                }
            }
        }
Example #4
0
 public TagBlockGuess(TagLayoutGuess layout, uint align)
 {
     if (layout == null)
         throw new ArgumentNullException("layout");
     ElementLayout = layout;
     Align = align;
 }
Example #5
0
 /// <summary>
 /// Merges another layout into this one.
 /// </summary>
 /// <param name="otherLayout">The layout to merge with.</param>
 public void Merge(TagLayoutGuess otherLayout)
 {
     if (otherLayout.Size != Size)
         Size = Math.Min(Size, otherLayout.Size); // hackhackhack
     foreach (var guess in otherLayout._guessesByOffset)
         Add(guess.Key, guess.Value);
 }
Example #6
0
        /// <summary>
        /// Makes a layout from a layout guess.
        /// </summary>
        /// <param name="layout">The layout guess.</param>
        /// <param name="name">The name of the final layout.</param>
        /// <param name="groupTag">The group tag of the final layout. Can be <c>null</c>.</param>
        /// <returns></returns>
        public static TagLayout MakeLayout(TagLayoutGuess layout, string name, Tag groupTag)
        {
            var result    = new TagLayout(name, layout.Size, groupTag);
            var finalizer = new LayoutGuessFinalizer(result, 0);

            finalizer.ProcessLayout(layout);
            return(result);
        }
Example #7
0
 public TagBlockGuess(TagLayoutGuess layout, uint align)
 {
     if (layout == null)
     {
         throw new ArgumentNullException("layout");
     }
     ElementLayout = layout;
     Align         = align;
 }
Example #8
0
 /// <summary>
 /// Merges another layout into this one.
 /// </summary>
 /// <param name="otherLayout">The layout to merge with.</param>
 public void Merge(TagLayoutGuess otherLayout)
 {
     if (otherLayout.Size != Size)
     {
         Size = Math.Min(Size, otherLayout.Size); // hackhackhack
     }
     foreach (var guess in otherLayout._guessesByOffset)
     {
         Add(guess.Key, guess.Value);
     }
 }
Example #9
0
 public TagLayoutGuess AnalyzeStructure(BinaryReader reader, uint count)
 {
     if (count == 0)
         throw new ArgumentException("count is 0", "count");
     var startOffset = (uint)reader.BaseStream.Position;
     if (!_tagMap.IsBoundary(startOffset))
         throw new InvalidOperationException("Cannot analyze a structure which does not start on a boundary");
     var endOffset = _tagMap.GetNextBoundary(startOffset);
     if (startOffset == endOffset)
         throw new InvalidOperationException("Structure is empty");
     var offset = startOffset;
     var elementSize = (endOffset - startOffset) / count;
     var result = new TagLayoutGuess(elementSize);
     for (var i = 0; i < count; i++)
     {
         AnalyzeStructure(reader, offset, elementSize, result);
         offset += elementSize;
         reader.BaseStream.Position = offset;
     }
     return result;
 }
Example #10
0
 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;
     }
 }
Example #11
0
        private void AnalyzeStructure(BinaryReader reader, uint baseOffset, uint size, TagLayoutGuess result)
        {
            var lookBehind = new uint[4];

            CachedTagData.PointerFixup potentialGuess = null;
            for (uint offset = 0; offset < size; offset += 4)
            {
                var val = reader.ReadUInt32();
                if (_resourceFixupsByWriteOffset.Contains(baseOffset + offset))
                {
                    // Value is a resource reference
                    result.Add(offset, new ResourceReferenceGuess());
                }
                else if (_dataFixupsByWriteOffset.TryGetValue(baseOffset + offset, out CachedTagData.PointerFixup 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.Index.Count)
                    {
                        var referencedTag = _cache.Index[(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;
            }
        }
 private void ProcessLayout(TagLayoutGuess layout)
 {
     for (uint offset = 0; offset < layout.Size; offset += 4)
     {
         var guess = layout.TryGet(offset);
         if (guess != null)
         {
             guess.Accept(offset, this);
             offset += guess.Size - 4;
         }
         else
         {
             var remaining = layout.Size - offset;
             switch (remaining)
             {
                 case 3:
                     _result.Add(MakeField(offset, BasicFieldType.Int16));
                     _result.Add(MakeField(offset, BasicFieldType.Int8));
                     break;
                 case 2:
                     _result.Add(MakeField(offset, BasicFieldType.Int16));
                     break;
                 case 1:
                     _result.Add(MakeField(offset, BasicFieldType.Int8));
                     break;
                 default: // >= 4
                     _result.Add(MakeField(offset, BasicFieldType.Int32));
                     break;
             }
         }
     }
 }