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)); }