Exemplo n.º 1
0
 /// <summary>
 /// Stream the field from a buffer
 /// </summary>
 /// <param name="input"></param>
 public override void Read(IO.EndianReader input)
 {
     if (StringType == StringType.Normal)
     {
         Value = input.ReadTagString();
     }
     else if (StringType == StringType.Unicode)
     {
         Value = input.ReadUnicodeString(Length);
     }
     else if (StringType == StringType.Ascii)
     {
         Value = input.ReadAsciiString(Length);
     }
     else if (StringType == StringType.Halo1Profile)
     {
         Value = input.ReadUnicodeString(12);
     }
     else if (StringType == StringType.Halo2Profile)
     {
         Value = input.ReadUnicodeString(16);
     }
     else if (StringType == StringType.CString)
     {
         Value = input.ReadCString();
     }
 }
Exemplo n.º 2
0
        /// <summary>
        /// Stream the field header data from a tag stream
        /// </summary>
        /// <param name="ts"></param>
        /// <exception cref="Exceptions.InvalidStringId"></exception>
        public override void ReadHeader(IO.ITagStream ts)
        {
            IO.EndianReader s = ts.GetInputStream();
            headerOffset = s.PositionUnsigned;             // nifty for debugging
            OwnerId      = ts.OwnerId;

            string value = null;

            try
            {
                if (fieldType == FieldType.OldStringId && ts.Flags.Test(IO.ITagStreamFlags.Halo2OldFormat_StringId))
                {
                    value = s.ReadAsciiString(28);                     // max of 28 characters in the string id in old builds
                }
                var owner = Program.GetTagIndex(OwnerId);
                Handle.Read(s, owner.StringIds.Definition.Description);

                if (value != null /*&& Handle != Blam.StringID.Null*/)
                {
                    owner.StringIds.TryAndGetStringId(value, out Handle);
                    Handle = new Blam.StringId(Handle.Description, Handle.Index, Handle.Length,
                                               -1);  // HACK used to tell Read that we already read the string data (as this is an old halo 2 tag)
                }
            }
            catch (Exception ex)
            {
                throw new Exceptions.InvalidStringId(ex,
                                                     base.headerOffset, uint.MaxValue,
                                                     ts, Handle.Length, value);
            }
        }
        /// <summary></summary>
        /// <param name="offsets">Buffer containing the offsets of the string values in <paramref name="buffer"/></param>
        /// <param name="buffer">Buffer containing the string values</param>
        /// <param name="is_packed">If true, reads the strings as null terminated strings, else as 128 character strings</param>
        /// <param name="count">Number of dynamic strings for <paramref name="set_index"/></param>
        /// <remarks>
        /// Doesn't use <paramref name="offsets"/> for reading the strings, assumes the strings are in sequential order in <paramref name="buffer"/>.
        ///
        /// Ignores <see cref="IsReadOnly"/>; will always add new IDs.
        /// </remarks>
        public void FromDebugStream(IO.EndianReader offsets, IO.EndianReader buffer,
                                    bool is_packed, int count)
        {
            if (count <= 0)
            {
                throw new ArgumentOutOfRangeException("count", count, "Must be greater than zero");
            }

            // Assume the strings are in sequential order in [buffer]
            offsets.Seek(sizeof(uint) * count, System.IO.SeekOrigin.Current);

            int set_index = InitialId.Set, initial_index = InitialId.Index;

            InitializeSet(count);
            for (int x = 0; x < count; x++)
            {
                var str = is_packed ? buffer.ReadCString() : buffer.ReadAsciiString(128);
                var sid = mOwner.Definition.Description.Generate(initial_index + x, str.Length, set_index);

                m_set.Set.Add(sid, str);

                int      hc = str.GetHashCode();
                StringId first_sid;
                if (m_set.SetLookup.TryGetValue(hc, out first_sid))
                {
                    Debug.Warn.If(false, "Hash collision! '{0}' ({1}) collides with '{2}' ({3})",
                                  m_set.Set[first_sid], first_sid.ToString(),
                                  str, sid.ToString());
                }
                else
                {
                    m_set.SetLookup.Add(str.GetHashCode(), sid);
                }
            }
        }
        public override void Read(IO.EndianReader s)
        {
            int k_local_sizeof = Blam.CacheFile.ValidateHeader(s, kSizeOf);

            s.Seek(4);
            version = s.ReadInt32();
            if (version != 11 && version != 12)
            {
                throw new InvalidCacheFileException(s.FileName);
            }
            fileLength = s.ReadInt32();
            s.ReadInt32();
            tagIndexAddress    = s.ReadUInt32();
            memoryBufferOffset = s.ReadInt32();
            memoryBufferSize   = s.ReadInt32();

            sourceFile = s.ReadAsciiString(256);
            build      = s.ReadTagString();
            cacheType  = (Blam.CacheType)s.ReadInt16();
            sharedType = (Cache.SharedType)s.ReadInt16();

            s.ReadBool();
            s.ReadBool();             // false if it belongs to a untracked build
            s.ReadBool();
            // PATCH: this is '3' in main menu patches
            s.ReadByte();             // appears to be an ODST-only field

            s.ReadInt32(); s.ReadInt32();
            s.ReadInt32(); s.ReadInt32(); s.ReadInt32();

            #region string id table
            // 0x158
            stringIdsCount        = s.ReadInt32();
            stringIdsBufferSize   = s.ReadInt32();
            stringIdIndicesOffset = s.ReadInt32();
            stringIdsBufferOffset = s.ReadInt32();
            #endregion

            #region filetimes?
            // pretty sure this is a flags field
            // used to tell which of the following 64bit values
            // are used. Damn sure this are FILETIME structures, but
            // hex workshop doesn't like them so I can't be for sure...
            needsShared             = s.ReadInt32() != 0; // just a little 'hack' if you will. if zero, the map is self reliant, so no worries
            Filetime.dwHighDateTime = s.ReadInt32();
            Filetime.dwLowDateTime  = s.ReadInt32();
            if (s.ReadInt32() != 0)
            {
                flags.Add(Halo3.CacheHeaderFlags.DependsOnMainMenu);
            }
            s.ReadInt32();
            if (s.ReadInt32() != 0)
            {
                flags.Add(Halo3.CacheHeaderFlags.DependsOnShared);
            }
            s.ReadInt32();
            if (s.ReadInt32() != 0)
            {
                flags.Add(Halo3.CacheHeaderFlags.DependsOnCampaign);
            }
            s.ReadInt32();
            #endregion

            name = s.ReadTagString();
            s.ReadInt32();
            scenarioPath = s.ReadAsciiString(256);
            // PATCH: this is -1 in main menu patches
            s.ReadInt32();             // minor version, normally not used

            #region tag paths
            tagNamesCount        = s.ReadInt32();
            tagNamesBufferOffset = s.ReadInt32();           // cstring buffer
            tagNamesBufferSize   = s.ReadInt32();           // cstring buffer total size in bytes
            tagNameIndicesOffset = s.ReadInt32();

            TagsUnknown1Count  = s.ReadInt32();
            TagsUnknown1Offset = s.ReadInt32();
            // PATCH: zero for non-patch data
            TagsUnknown2Count  = s.ReadInt32();
            TagsUnknown2Offset = s.ReadInt32();
            #endregion

            checksum = s.ReadUInt32();                // 0x2D4
            s.Seek(32, System.IO.SeekOrigin.Current); // these bytes are always the same. first 8 changed in Halo4

            baseAddress = s.ReadUInt32();             // expected base address
            xdkVersion  = s.ReadInt32();              // xdk version

            #region memory partitions
            // 0x300

            // memory partitions
            memoryPartitions = new Partition[6];
            memoryPartitions[0].BaseAddress = s.ReadUInt32();             // cache resource buffer
            memoryPartitions[0].Size        = s.ReadInt32();

            // readonly
            memoryPartitions[1].BaseAddress = s.ReadUInt32();             // cache gestalt resource buffer
            memoryPartitions[1].Size        = s.ReadInt32();

            memoryPartitions[2].BaseAddress = s.ReadUInt32();             // global tags buffer (cache sound tags likes this memory space too)
            memoryPartitions[2].Size        = s.ReadInt32();
            memoryPartitions[3].BaseAddress = s.ReadUInt32();             // shared tag blocks? (havok data likes this memory space too)
            memoryPartitions[3].Size        = s.ReadInt32();
            memoryPartitions[4].BaseAddress = s.ReadUInt32();             // address
            memoryPartitions[4].Size        = s.ReadInt32();

            // readonly
            memoryPartitions[5].BaseAddress = s.ReadUInt32();             // map tags buffer
            memoryPartitions[5].Size        = s.ReadInt32();
            #endregion

            int count = s.ReadInt32();
            s.Seek(4 + 8, System.IO.SeekOrigin.Current);             // these bytes are always the same
            // if there is a hash in the header, this is the ONLY
            // place where it can be
            s.Seek(20 /*SHA1*/ + 40 + 256 /*RSA*/, System.IO.SeekOrigin.Current);             // ???

            // 0x47C
            cacheInterop.Read(s);
            cacheInterop.PostprocessForCacheRead(k_local_sizeof);

            s.Seek(16, System.IO.SeekOrigin.Current);             // GUID?, these bytes are always the same. ODST is different from Halo 3

            // PATCH: main menu patches have a single entry (where stock has none)
            #region blah 1
            // 0x4AC

            // campaign has a shit load of these
            // but shared doesn't nor mainmenu
            // I compared the sc110 french and english and both have the SAME counts and element data. So
            // I don't think this is a hash or something. At least, if it is, it's not runtime relative so
            // nothing we have to worry about

            s.ReadInt16();             // I've only seen this be two different values (besides zero).
            count = s.ReadInt16();     // I think the above specifies the size of the structure this count represents?
            s.ReadInt32();             // seems to always be zero
            CompressionGuid = new Guid(s.ReadBytes(16));

            s.Seek(count * 28, System.IO.SeekOrigin.Current);             // seek past the elements
            // dword
            // long
            // buffer [0x14] (probably a sha1 hash)
            s.Seek((3600 - count) * 28, System.IO.SeekOrigin.Current);             // seek past the unused elements
            #endregion

            // PATCH: main menu patches have a count of '1' but doesn't appear to have
            #region blah 2
            s.Seek(sizeof(uint) + 0x4E9C, System.IO.SeekOrigin.Current);
#if false
            {
                // 0x18E94

                // going to punt and just assume there is a max count of 13 of these possible

                // maybe related to bsp\'zones'?
                const int blah2_sizeof = 0x60C;

                count = (int)(s.ReadUInt32() >> 24);                               // did someone forget to f*****g byte swap something?
                s.Seek(count * blah2_sizeof, System.IO.SeekOrigin.Current);        // seek past the elements
                s.Seek((13 - count) * blah2_sizeof, System.IO.SeekOrigin.Current); // seek past the unused elements
            }
#endif
            #endregion

            s.Seek(712 + sizeof(uint), System.IO.SeekOrigin.Current);


            ReadPostprocessForInterop();

            if (!cacheInterop.IsNull)
            {
                int debug_mask = (int)cacheInterop[CacheSectionType.Debug].AddressMask;
                if (TagsUnknown1Offset != 0)
                {
                    TagsUnknown1Offset -= debug_mask;
                }
                if (TagsUnknown2Offset != 0)
                {
                    TagsUnknown2Offset -= debug_mask;
                }
            }

            ReadPostprocessForBaseAddresses(s);
        }