public static StringTableContainer FromData(SaveState state)
            {
                int stringTableCount = state.ReadVariableLengthOffset();

                var reader    = state.Reader;
                var container = new StringTableContainer();

                for (int i = 0; i < stringTableCount; i++)
                {
                    int blockCount = reader.ReadInt32();

                    if (blockCount < 0)
                    {
                        return(null);
                    }

                    int blockSize = reader.ReadInt32();

                    if (blockSize < 0)
                    {
                        return(null);
                    }

                    if ((blockCount * blockSize) > reader.StreamRemainder() ||
                        ((blockSize - 1) & blockSize) != 0)
                    {
                        return(null);
                    }

                    var table = new Table()
                    {
                        BitShiftMask = BitOperations.TrailingZeroCount(blockSize),
                        BlockCount   = blockCount,
                        BlockSize    = blockSize,
                        Data         = new byte[blockCount][],
                    };

                    for (int j = 0; j < table.BlockCount; j++)
                    {
                        table.Data[j] = reader.ReadBytesStrict(table.BlockSize);
                    }

                    // No clue what this is
                    int unknownCount = reader.ReadInt32();

                    if (unknownCount < 0 || (unknownCount * 8) > reader.StreamRemainder())
                    {
                        return(null);
                    }

                    table.UnknownData = reader.ReadBytesStrict(unknownCount * 8);

                    // Insert
                    container.Tables.Add(table);
                }

                return(container);
            }
        private void ReadHeaderData()
        {
            Reader.BaseStream.Position = SaveDataOffset + SaveDataLength - 0x8;
            uint typeDataChunkOffset = Reader.ReadUInt32();
            uint rawDataChunkOffset  = Reader.ReadUInt32();

            // String/GUID tables
            Reader.BaseStream.Position = SaveDataOffset + rawDataChunkOffset;
            {
                // UTF-8 strings
                StringPool = StringTableContainer.FromData(this);

                // UTF-16 strings
                WideStringPool = WideStringTableContainer.FromData(this);

                // GUIDs
                if (SaveVersion >= 26)
                {
                    GUIDPool = GUIDTableContainer.FromData(this);
                }
            }

            // Serialized type information and object instances
            Reader.BaseStream.Position = SaveDataOffset + typeDataChunkOffset;
            {
                // Create basic objects that are immediately registered with the engine
                int objectInstanceTypeCount = ReadVariableLengthOffset();
                LocalSaveObjects = new Dictionary <int, object>();

                for (int i = 0; i < objectInstanceTypeCount; i++)
                {
                    Type objectType    = RTTI.GetTypeByName(ReadIndexedString());
                    int  instanceCount = ReadVariableLengthOffset();

                    for (int j = 0; j < instanceCount; j++)
                    {
                        int objectId = ReadVariableLengthOffset();

                        LocalSaveObjects.Add(objectId, RTTI.CreateObjectInstance(objectType));
                    }
                }

                // Handles to game data objects
                int gameDataObjectCount = ReadVariableLengthOffset();
                GameDataObjects = new Dictionary <int, BaseGGUUID>();

                for (int i = 0; i < gameDataObjectCount; i++)
                {
                    int objectId = ReadVariableLengthOffset();
                    var guid     = new BaseGGUUID().FromData(Reader);

                    GameDataObjects.Add(objectId, guid);
                }

                // RTTI/class member layouts
                RTTIContainer = RTTIMapContainer.FromData(this);

                // File prefetch
                int prefetchFileCount = ReadVariableLengthOffset();
                PrefetchFilePaths = new List <string>(prefetchFileCount);

                for (int i = 0; i < prefetchFileCount; i++)
                {
                    PrefetchFilePaths.Add(ReadIndexedString());
                }
            }

            Reader.BaseStream.Position = SaveDataOffset;
        }