Example #1
0
 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;
     }
 }
        public void Begin(MagicNumber tagClass, int classStringId, TagLayoutGuess layout)
        {
            if (_writer != null)
                throw new InvalidOperationException("Cannot begin a new tag while another is still in progress");

            // Convert the class name to a pascal case string and use that as the file name
            var name = _stringIds.GetString(classStringId);
            if (string.IsNullOrEmpty(name))
                throw new InvalidOperationException("Unable to look up the tag class name");
            name = ConvertToPascalCase(name);
            var path = Path.Combine(_outDir, name + ".hpp");
            _writer = new StreamWriter(File.Open(path, FileMode.Create, FileAccess.Write));

            // Write the C++ header
            _writer.WriteLine("#pragma once");
            _writer.WriteLine("#include \"Tags.hpp\"");
            _writer.WriteLine();
            _writer.WriteLine("namespace Blam");
            _writer.WriteLine("{");
            _writer.WriteLine("\tnamespace Tags");
            _writer.WriteLine("\t{");

            _builder = new StructBuilder(_writer, 2, name);
            _builder.Begin(tagClass, classStringId, layout);
        }
        public void Begin(MagicNumber tagClass, int classStringId, TagLayoutGuess layout)
        {
            if (_writer != null)
                throw new InvalidOperationException("Cannot begin a new tag while another is still in progress");

            // Convert the class name to a pascal case string and use that as the file name
            var name = _stringIds.GetString(classStringId);
            if (string.IsNullOrEmpty(name))
                throw new InvalidOperationException("Unable to look up the tag class name");
            name = ConvertToPascalCase(name);
            var path = Path.Combine(_outDir, name + ".cs");
            _writer = new StreamWriter(File.Open(path, FileMode.Create, FileAccess.Write));

            // Write the C# header
            _writer.WriteLine("using System;");
            _writer.WriteLine("using System.Collections.Generic;");
            _writer.WriteLine("using System.Linq;");
            _writer.WriteLine("using System.Text;");
            _writer.WriteLine("using System.Threading.Tasks;");
            _writer.WriteLine("using EldoradoLib.Serialization;");
            _writer.WriteLine();
            _writer.WriteLine("namespace EldoradoLib.TagStructures");
            _writer.WriteLine("{");

            _builder = new ClassBuilder(_writer, 1, name);
            _builder.Begin(tagClass, classStringId, layout);
        }
Example #4
0
 /// <summary>
 /// Merges anoter 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 #5
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;
 }
        public static void Write(HaloTag tag, TagLayoutGuess layout, ITagLayoutWriter writer)
        {
            if (tag != null)
                writer.Begin(tag.Class, tag.ClassId, layout);
            else
                writer.Begin(new MagicNumber(0), 0, layout);

            for (uint offset = 0; offset < layout.Size; offset += 4)
            {
                var guess = layout.TryGet(offset);
                if (guess != null)
                {
                    writer.AddGuess(offset, guess);
                    offset += guess.Size - 4;
                }
                else
                {
                    var remaining = layout.Size - offset;
                    switch (remaining)
                    {
                        case 3:
                            writer.AddUnknownInt16(offset);
                            writer.AddUnknownByte(offset + 2);
                            break;
                        case 2:
                            writer.AddUnknownInt16(offset);
                            break;
                        case 1:
                            writer.AddUnknownByte(offset);
                            break;
                        default: // >= 4
                            writer.AddUnknownInt32(offset);
                            break;
                    }
                }
            }
            writer.End();
        }
 public void Begin(MagicNumber tagClass, int classStringId, TagLayoutGuess layout)
 {
     _size = layout.Size;
     if (tagClass.Value != 0)
         _writer.WriteLine("{0}struct {1} : Tag<'{2}'>", _indent, _name, tagClass);
     else
         _writer.WriteLine("{0}struct {1}", _indent, _name);
     _writer.WriteLine("{0}{{", _indent);
     SetIndent(_indentLevel + 1);
 }
Example #8
0
 public TagBlockGuess(TagLayoutGuess layout)
 {
     if (layout == null)
         throw new ArgumentNullException("layout");
     ElementLayout = layout;
 }
 public void Begin(MagicNumber tagClass, int classStringId, TagLayoutGuess layout)
 {
     if (classStringId != 0)
         _writer.WriteLine("{0}[TagStructure(Class = \"{1}\", Size = 0x{2:X})]", _indent, tagClass, layout.Size);
     else
         _writer.WriteLine("{0}[TagStructure(Size = 0x{1:X})]", _indent, layout.Size);
     _writer.WriteLine("{0}public class {1}", _indent, _name);
     _writer.WriteLine("{0}{{", _indent);
     SetIndent(_indentLevel + 1);
 }