/// <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;
 }
        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;
                    }
                }
            }
        }
        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, StringId 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 HaloOnlineTagTool.Serialization;");
            _writer.WriteLine();
            _writer.WriteLine("namespace HaloOnlineTagTool.TagStructures");
            _writer.WriteLine("{");

            _builder = new ClassBuilder(_writer, 1, name);
            _builder.Begin(tagClass, classStringId, layout);
        }
 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 TagBlockGuess(TagLayoutGuess layout, uint align)
 {
     if (layout == null)
         throw new ArgumentNullException("layout");
     ElementLayout = layout;
     Align = align;
 }
 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 #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);
        }
        public void Begin(MagicNumber tagClass, StringId 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 HaloOnlineTagTool.Serialization;");
            _writer.WriteLine();
            _writer.WriteLine("namespace HaloOnlineTagTool.TagStructures");
            _writer.WriteLine("{");

            _builder = new ClassBuilder(_writer, 1, name);
            _builder.Begin(tagClass, classStringId, layout);
        }
 /// <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 #12
0
 public TagBlockGuess(TagLayoutGuess layout)
 {
     if (layout == null)
     {
         throw new ArgumentNullException("layout");
     }
     ElementLayout = layout;
 }
        /// <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 #14
0
 public TagBlockGuess(TagLayoutGuess layout, uint align)
 {
     if (layout == null)
     {
         throw new ArgumentNullException("layout");
     }
     ElementLayout = layout;
     Align         = align;
 }
Example #15
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);
     }
 }
 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);
 }
 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 #18
0
        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 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), StringId.Null, 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();
        }
Example #21
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;
            }
        }
 public void Begin(MagicNumber tagClass, StringId classStringId, TagLayoutGuess layout)
 {
     if (classStringId != StringId.Null)
         _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);
 }
Example #23
0
		public TagBlockGuess(TagLayoutGuess layout)
		{
			if (layout == null)
				throw new ArgumentNullException("layout");
			ElementLayout = layout;
		}
 public void Begin(MagicNumber tagClass, StringId 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);
 }