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);
        }
Exemplo n.º 2
0
        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);
        }
Exemplo n.º 3
0
 /// <summary>
 /// Determines whether the tag is an instance of a given tag class identifier.
 /// </summary>
 /// <param name="tagClass">The tag class.</param>
 /// <returns><c>true</c> if the tag is an instance of the given class identifier.</returns>
 public bool IsClass(MagicNumber tagClass)
 {
     if (tagClass.Value == -1)
         return false;
     return (Class == tagClass || ParentClass == tagClass || GrandparentClass == tagClass);
 }
Exemplo n.º 4
0
        private void ReadTagHeader(BinaryReader reader, HaloTag resultTag)
        {
            var headerOffset = (uint)reader.BaseStream.Position;
            var checksum = reader.ReadUInt32();                         // 0x00 uint32 checksum?
            var totalSize = reader.ReadUInt32();                        // 0x04 uint32 total size
            var numDependencies = reader.ReadInt16();                   // 0x08 int16  dependencies count
            var numDataFixups = reader.ReadInt16();                     // 0x0A int16  data fixup count
            var numResourceFixups = reader.ReadInt16();                 // 0x0C int16  resource fixup count
            reader.BaseStream.Position += 2;                            // 0x0E int16  (padding)
            var mainStructOffset = reader.ReadUInt32();                 // 0x10 uint32 main struct offset
            var tagClass = new MagicNumber(reader.ReadInt32());         // 0x14 int32  class
            var parentClass = new MagicNumber(reader.ReadInt32());      // 0x18 int32  parent class
            var grandparentClass = new MagicNumber(reader.ReadInt32()); // 0x1C int32  grandparent class
            var classId = reader.ReadInt32();                           // 0x20 uint32 class stringid
            var totalHeaderSize = CalculateHeaderSize(numDependencies, numDataFixups, numResourceFixups);

            // Update the tag object
            _tagClasses.Add(tagClass);
            resultTag.Class = tagClass;
            resultTag.ParentClass = parentClass;
            resultTag.GrandparentClass = grandparentClass;
            resultTag.MainStructOffset = mainStructOffset - totalHeaderSize;
            resultTag.Offset = headerOffset + totalHeaderSize;
            resultTag.Size = totalSize - totalHeaderSize;
            resultTag.Checksum = checksum;
            resultTag.ClassId = classId;

            // Read dependencies
            resultTag.Dependencies.Clear();
            for (var j = 0; j < numDependencies; j++)
                resultTag.Dependencies.Add(reader.ReadInt32());

            // Read fixup pointers
            var dataFixupPointers = new uint[numDataFixups];
            for (var j = 0; j < numDataFixups; j++)
                dataFixupPointers[j] = reader.ReadUInt32();
            var resourceFixupPointers = new uint[numResourceFixups];
            for (var j = 0; j < numResourceFixups; j++)
                resourceFixupPointers[j] = reader.ReadUInt32();

            // Process fixups
            resultTag.DataFixups.Clear();
            resultTag.ResourceFixups.Clear();
            foreach (var fixup in dataFixupPointers)
                resultTag.DataFixups.Add(ReadFixup(reader, fixup, headerOffset, totalHeaderSize));
            foreach (var fixup in resourceFixupPointers)
                resultTag.ResourceFixups.Add(ReadFixup(reader, fixup, headerOffset, totalHeaderSize));
        }
Exemplo n.º 5
0
 /// <summary>
 /// Determines whether or not a tag with the given class exists.
 /// </summary>
 /// <param name="tagClass">The tag class.</param>
 /// <returns><c>true</c> if a tag with the given class exists.</returns>
 public bool ContainsClass(MagicNumber tagClass)
 {
     return _tagClasses.Contains(tagClass);
 }
Exemplo n.º 6
0
 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);
 }
 /// <summary>
 /// Finds a global tag by its class identifier.
 /// </summary>
 /// <param name="tagClass">The tag class identifier.</param>
 /// <returns>The global tag if found, or <c>null</c> otherwise.</returns>
 public HaloTag FindTag(MagicNumber tagClass)
 {
     return Tags.FirstOrDefault(t => t.IsClass(tagClass));
 }
Exemplo n.º 8
0
 /// <summary>
 /// 检查 二进制数据 是否为 SQLite3 数据库文件
 /// </summary>
 /// <param name="buffer"></param>
 /// <returns></returns>
 public static bool IsSQLite3(IReadOnlyList <byte> buffer)
 => MagicNumber.SequenceEqual(buffer, DataBaseFileFormat.SQLite3.MagicNumber);
Exemplo n.º 9
0
        public BUVChunk(Stream stream)
        {
            BinaryReader reader = new BinaryReader(stream);

            MagicNumber = Encoding.ASCII.GetString(reader.ReadBytes(4));
            if (MagicNumber != ExpectedMagicNumber)
            {
                throw new UnknownMagicException(string.Format("Unexpected '{0}' for BUV", new string(MagicNumber.Where(x => !Char.IsControl(x)).ToArray()).TrimEnd('\0')));
            }

            NumEntries = reader.ReadUInt32();

            Entries = new BUVEntry[NumEntries];
            for (int i = 0; i < Entries.Length; i++)
            {
                Entries[i] = new BUVEntry(stream);
            }
        }
Exemplo n.º 10
0
        public void SaveXml(string filename)
        {
            var xml  = new XDocument();
            var root = new XElement("CombinedMoveFile");

            root.SetAttributeValue("Version", 1);
            root.SetAttributeValue("Count", MoveCount);

            var srl = new NomadXmlSerializer();

            //foreach (var child in Root.Children)
            //    srl.CreateXmlElement(child, root);

            var fixups = new List <(int offset, int hash, string param)>();

            foreach (var param in AllParams)
            {
                foreach (var fixup in param.Fixups)
                {
                    fixups.Add((fixup.Offset, fixup.Hash, param.Name));
                }
            }

            fixups = fixups.OrderBy((e) => e.offset).ToList();

            var resources = new List <MoveResourceData>();
            var offset    = 0;

            foreach (var info in PerMoveResourceInfo.Infos)
            {
                var hash  = BitConverter.ToInt32(MoveData, offset);
                var bound = (offset + info.Size);

                var resource = new MoveResourceData();
                var hashes   = new List <int>();

                foreach (var fixup in fixups.Where((e) => e.offset > offset))
                {
                    if (fixup.offset > bound)
                    {
                        break;
                    }

                    var param       = resource.AllParams.First((m) => m.Name == fixup.param);
                    var globalParam = AllParams.First((m) => m.Name == fixup.param);

                    var fixupInfo = new FixupInfo(fixup.hash, fixup.offset - offset);

                    param.Fixups.Add(fixupInfo);

                    // add value once
                    if (!hashes.Contains(fixup.hash))
                    {
                        hashes.Add(fixup.hash);

                        foreach (var value in globalParam.Values)
                        {
                            var hashAttr = value.GetAttribute("hash");
                            var hashData = hashAttr.Data;

                            int paramHash = 0;

                            // HACKS!!!!!
                            if (hashData.Size < 4)
                            {
                                if (hashData.Size == 1)
                                {
                                    paramHash = (sbyte)hashData.Buffer[0];
                                }
                                else
                                {
                                    paramHash = Utils.UnpackData(hashAttr, BitConverter.ToInt16);
                                }
                            }
                            else
                            {
                                paramHash = Utils.UnpackData(hashAttr, BitConverter.ToInt32);
                            }

                            if (paramHash == fixup.hash)
                            {
                                param.Values.Add(value);
                                break;
                            }
                        }
                    }
                }

                var buffer = new byte[info.Size];

                Buffer.BlockCopy(MoveData, offset, buffer, 0, info.Size);

                resource.RootNodeId = info.RootNodeId;
                resource.MoveData   = buffer;

                resources.Add(resource);

                offset += info.Size;
            }

            foreach (var resource in resources)
            {
                srl.CreateXmlElement(resource.ToObject(), root);
            }

#if PATCH_FIXUP_TAGS
            var buffer = new byte[MoveData.Length];

            Buffer.BlockCopy(MoveData, 0, buffer, 0, buffer.Length);

            foreach (var param in AllParams)
            {
                if (param.Tag == "xxxx")
                {
                    continue;
                }

                MagicNumber mgx = param.Tag;

                var tag = BitConverter.GetBytes((int)mgx);

                foreach (var fixup in param.Fixups)
                {
                    Buffer.BlockCopy(tag, 0, buffer, fixup.Offset, tag.Length);
                }
            }

            File.WriteAllBytes(Path.ChangeExtension(filename, ".tags.bin"), buffer);
#endif
#if DUMP_FIXUP_LOG_INFO
            var dbg = new List <(int offset, string name, int old, int hash)>();
            var sb  = new StringBuilder();

            foreach (var param in AllParams)
            {
                var idx = 0;

                foreach (var fixup in param.Fixups)
                {
                    var orig = BitConverter.ToInt32(MoveData, fixup.Offset);

                    dbg.Add((fixup.Offset, $"{param.Name} fixup {idx++}", orig, fixup.Hash));
                }
            }

            var fixups = dbg.OrderBy((e) => e.offset).ToList();

            var infoOffset = 0;
            var infoIndex  = 0;

            var rootDir = Path.GetDirectoryName(filename);
            var outDir  = Path.Combine(rootDir, "movedata_files");

            if (!Directory.Exists(outDir))
            {
                Directory.CreateDirectory(outDir);
            }

            foreach (var info in PerMoveResourceInfo.Infos)
            {
                var hash = BitConverter.ToInt32(MoveData, infoOffset);

                var unk_04 = BitConverter.ToInt32(MoveData, infoOffset + 4);

                var unk_08 = MoveData[infoOffset + 8];
                var unk_09 = MoveData[infoOffset + 9];
                var unk_0a = MoveData[infoOffset + 10];
                var unk_0b = MoveData[infoOffset + 11];

                sb.AppendLine($"MoveData({hash:X8})[{infoIndex++}] @ {infoOffset:X8}");
                sb.AppendLine($"  Unk_04: {unk_04}");
                sb.AppendLine($"  Unk_08: ({unk_08}, {unk_09}, {unk_0a}, {unk_0b})");
                sb.AppendLine($"  RootNodeId: {info.RootNodeId:X8}");

                var upperBound = (infoOffset + info.Size);

                var fixupOffset = infoOffset;

                foreach (var fixup in fixups.Where((e) => e.offset < upperBound))
                {
                    if (fixup.offset < infoOffset)
                    {
                        continue;
                    }

                    sb.AppendLine($" - {fixup.offset - infoOffset:X8}: {fixup.old:X8} -> {fixup.hash:X8} ; {fixup.name}");
                }

                var buffer = new byte[info.Size];

                Buffer.BlockCopy(MoveData, infoOffset, buffer, 0, info.Size);
                File.WriteAllBytes(Path.Combine(outDir, $"{unk_08}_{unk_09}_{unk_0a}_{unk_0b}#{hash:X8}.bin"), buffer);

                infoOffset += info.Size;
            }

            //var dbgTxt = String.Join("\r\n", dbg.OrderBy((e) => e.offset).Select((e) => $"{e.offset:X8}: {e.old:X8} -> {e.hash:X8} ; {e.name}"));
            //sb.Append(dbgTxt);

            File.WriteAllBytes(Path.ChangeExtension(filename, ".data.bin"), MoveData);
            File.WriteAllText(Path.ChangeExtension(filename, ".debug.log"), sb.ToString());
#endif
            xml.Add(root);
            xml.SaveFormatted(filename, true);
        }
Exemplo n.º 11
0
 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);
 }
Exemplo n.º 12
0
        public void TestConstructingFromInteger()
        {
            var magic = new MagicNumber(42);

            Assert.AreEqual(42, magic.Value);
        }
 /// <summary>
 /// Finds a global tag by its class identifier.
 /// </summary>
 /// <param name="tagClass">The tag class identifier.</param>
 /// <returns>The global tag if found, or <c>null</c> otherwise.</returns>
 public HaloTag FindTag(MagicNumber tagClass)
 {
     return(Tags.FirstOrDefault(t => t.IsClass(tagClass)));
 }
Exemplo n.º 14
0
        public SceGxtHeader(Stream stream)
        {
            BinaryReader reader = new BinaryReader(stream);

            MagicNumber = Encoding.ASCII.GetString(reader.ReadBytes(4));
            if (MagicNumber != ExpectedMagicNumber)
            {
                throw new UnknownMagicException(string.Format("Unexpected '{0}' for GTX", new string(MagicNumber.Where(x => !Char.IsControl(x)).ToArray()).TrimEnd('\0')));
            }

            Version           = reader.ReadUInt32();
            NumTextures       = reader.ReadUInt32();
            TextureDataOffset = reader.ReadUInt32();
            TextureDataSize   = reader.ReadUInt32();
            NumP4Palettes     = reader.ReadUInt32();
            NumP8Palettes     = reader.ReadUInt32();
            Padding           = reader.ReadUInt32();
        }
Exemplo n.º 15
0
 /// <summary>
 /// 检查 流中的数据 是否为 SQLite3 数据库文件
 /// </summary>
 /// <param name="stream"></param>
 /// <returns></returns>
 public static bool IsSQLite3(Stream stream)
 => IsSQLite3(MagicNumber.ReadHeaderBuffer(stream, DataBaseFileFormat.SQLite3.MagicNumber.Length));
Exemplo n.º 16
0
        protected override void ReadContentFrom(BinaryReader input)
        {
            //Type      Name            Description
            //uint16    majorVersion    Major version number of the font header table — set to 1.
            //uint16    minorVersion    Minor version number of the font header table — set to 0.
            //Fixed     fontRevision    Set by font manufacturer.
            //uint32    checkSumAdjustment  To compute: set it to 0, sum the entire font as uint32, then store 0xB1B0AFBA - sum.
            //                          If the font is used as a component in a font collection file,
            //                          the value of this field will be invalidated by changes to the file structure and font table directory, and must be ignored.
            //uint32    magicNumber     Set to 0x5F0F3CF5.
            //uint16    flags           Bit 0: Baseline for font at y=0;

            //                          Bit 1: Left sidebearing point at x=0 (relevant only for TrueType rasterizers) — see the note below regarding variable fonts;

            //                          Bit 2: Instructions may depend on point size;

            //                          Bit 3: Force ppem to integer values for all internal scaler math; may use fractional ppem sizes if this bit is clear;

            //                          Bit 4: Instructions may alter advance width (the advance widths might not scale linearly);

            //                          Bit 5: This bit is not used in OpenType, and should not be set in order to ensure compatible behavior on all platforms. If set, it may result in different behavior for vertical layout in some platforms. (See Apple’s specification for details regarding behavior in Apple platforms.)

            //                          Bits 6–10: These bits are not used in Opentype and should always be cleared. (See Apple’s specification for details regarding legacy used in Apple platforms.)

            //                          Bit 11: Font data is “lossless” as a result of having been subjected to optimizing transformation and/or compression (such as e.g. compression mechanisms defined by ISO/IEC 14496-18, MicroType Express, WOFF 2.0 or similar) where the original font functionality and features are retained but the binary compatibility between input and output font files is not guaranteed. As a result of the applied transform, the DSIG table may also be invalidated.

            //                          Bit 12: Font converted (produce compatible metrics)

            //                          Bit 13: Font optimized for ClearType™. Note, fonts that rely on embedded bitmaps (EBDT) for rendering should not be considered optimized for ClearType, and therefore should keep this bit cleared.

            //                          Bit 14: Last Resort font. If set, indicates that the glyphs encoded in the 'cmap' subtables are simply generic symbolic representations of code point ranges and don’t truly represent support for those code points. If unset, indicates that the glyphs encoded in the 'cmap' subtables represent proper support for those code points.

            //                          Bit 15: Reserved, set to 0
            //uint16        unitsPerEm  Set to a value from 16 to 16384. Any value in this range is valid.
            //                          In fonts that have TrueType outlines, a power of 2 is recommended as this allows performance optimizations in some rasterizers.
            //LONGDATETIME  created     Number of seconds since 12:00 midnight that started January 1st 1904 in GMT/UTC time zone. 64-bit integer
            //LONGDATETIME  modified    Number of seconds since 12:00 midnight that started January 1st 1904 in GMT/UTC time zone. 64-bit integer
            //int16     xMin            For all glyph bounding boxes.
            //int16     yMin            For all glyph bounding boxes.
            //int16     xMax            For all glyph bounding boxes.
            //int16     yMax            For all glyph bounding boxes.
            //uint16    macStyle        Bit 0: Bold (if set to 1);
            //                          Bit 1: Italic (if set to 1)
            //                          Bit 2: Underline (if set to 1)
            //                          Bit 3: Outline (if set to 1)
            //                          Bit 4: Shadow (if set to 1)
            //                          Bit 5: Condensed (if set to 1)
            //                          Bit 6: Extended (if set to 1)
            //                          Bits 7–15: Reserved (set to 0).
            //uint16    lowestRecPPEM   Smallest readable size in pixels.
            //int16     fontDirectionHint   Deprecated (Set to 2).
            //                          0: Fully mixed directional glyphs;
            //                          1: Only strongly left to right;
            //                          2: Like 1 but also contains neutrals;
            //                          -1: Only strongly right to left;
            //                          -2: Like -1 but also contains neutrals.

            //(A neutral character has no inherent directionality; it is not a character with zero (0) width. Spaces and punctuation are examples of neutral characters. Non-neutral characters are those with inherent directionality. For example, Roman letters (left-to-right) and Arabic letters (right-to-left) have directionality. In a “normal” Roman font where spaces and punctuation are present, the font direction hints should be set to two (2).)
            //int16     indexToLocFormat    0 for short offsets (Offset16), 1 for long (Offset32).
            //int16     glyphDataFormat     0 for current format.


            Version            = input.ReadUInt32(); // 0x00010000 for version 1.0.
            FontRevision       = input.ReadUInt32();
            CheckSumAdjustment = input.ReadUInt32();
            MagicNumber        = input.ReadUInt32();
            if (MagicNumber != 0x5F0F3CF5)
            {
                throw new Exception("Invalid magic number!" + MagicNumber.ToString("x"));
            }

            Flags      = input.ReadUInt16();
            UnitsPerEm = input.ReadUInt16(); // valid is 16 to 16384
            Created    = input.ReadUInt64(); //  International date (8-byte field). (?)
            Modified   = input.ReadUInt64();
            // bounding box for all glyphs
            Bounds            = Utils.ReadBounds(input);
            MacStyle          = input.ReadUInt16();
            LowestRecPPEM     = input.ReadUInt16();
            FontDirectionHint = input.ReadInt16();
            _indexToLocFormat = input.ReadInt16(); // 0 for 16-bit offsets, 1 for 32-bit.
            GlyphDataFormat   = input.ReadInt16(); // 0
        }