Exemple #1
0
        private string LookupStringTable(ushort identifier)
        {
            StringTable strTable = GetStringTableByIdentifier(identifier);

            identifier -= strTable.identifierOffset;

            IntPtr indexerTable = reader.ReadAddress32(strTable.indexTable, AddressingMode.Relative);

            if (indexerTable == IntPtr.Zero)
            {
                return(null);
            }

            IntPtr addressTable = reader.ReadAddress32(strTable.addressTable, AddressingMode.Relative);

            if (addressTable == IntPtr.Zero)
            {
                return(null);
            }

            /*
             *  Info by [qhris].
             *
             *  Unicode strings are stored contiguous in a big buffer. To access this buffer
             *  the address table is used. The address table maps an address index to a string
             *  in the contiguous buffer.
             *
             *  Note that all strings end with a null terminator and string length does not seem to
             *  be stored anywhere.
             *
             *  To get the address index, the string identifier (unsigned short) is looked up in the
             *  item info table, along with a few checks to validate.
             */
            var tableInfo = reader.Read <D2StringTableInfo>(indexerTable);

            // We use the identifier 0x1F4 for invalid identifiers.
            // because this is also what happens in D2Lang.dll
            if (identifier >= tableInfo.IdentifierCount)
            {
                identifier = 0x01F4;
            }

            // Right after the string info table (in memory) lies the identifier -> address index
            // mapping array.
            IntPtr stringDataRegion = indexerTable + Marshal.SizeOf <D2StringTableInfo>();
            Func <ushort, IntPtr> GetAddressIndexLocation = (index) => stringDataRegion + index * sizeof(ushort);

            // Read address index; must be in valid range.
            ushort addressTableIndex = reader.ReadUInt16(GetAddressIndexLocation(identifier));

            if (addressTableIndex >= tableInfo.AddressTableSize)
            {
                return(null);
            }

            // Get the address containing string information.
            IntPtr stringInfoBlock   = GetAddressIndexLocation(tableInfo.IdentifierCount);
            IntPtr stringInfoAddress = stringInfoBlock + addressTableIndex * Marshal.SizeOf <D2StringInfo>();

            // Make sure it's in range.
            IntPtr endTest = indexerTable + tableInfo.DataBlockSize;

            if ((long)stringInfoAddress >= (long)endTest)
            {
                return(null);
            }

            // Check if the string has been loaded into the address table.
            D2StringInfo stringInfo = reader.Read <D2StringInfo>(stringInfoAddress);

            if (!stringInfo.IsLoadedUnicode)
            {
                return(null);
            }

            // If we get a null string address, just ignore it.
            IntPtr stringAddress = reader.ReadAddress32(addressTable + addressTableIndex * sizeof(uint));

            if (stringAddress == IntPtr.Zero)
            {
                return(null);
            }

            // A maximum of 0x4000 sized buffer **should** be enough to read all strings, bump if too low.
            return(reader.GetNullTerminatedString(stringAddress, 0x100, 0x4000, Encoding.Unicode, AddressingMode.Absolute));
        }