protected override void Parse(ref BitStreamReader bsr) { StringTablesManager manager = DemoRef.StringTablesManager; if (!manager.TableReadable.GetValueOrDefault(_tableName)) { DemoRef.LogError($"{_tableName} table is marked as non-readable, can't update :/"); _exceptionWhileParsing = true; bsr.SkipToEnd(); return; } if (manager.CreationLookup.Single(table => table.TableName == _tableName).Flags == StringTableFlags.Fake) { DemoRef.LogError($"{_tableName} table was created manually - not parsed in SvcServerInfo"); _exceptionWhileParsing = true; bsr.SkipToEnd(); return; } try { // se2007/engine/networkstringtable.cpp line 595 MutableStringTable tableToUpdate = manager.Tables[_tableName]; int?decompressedIndex = null; if (tableToUpdate.Flags.HasValue && (tableToUpdate.Flags & StringTableFlags.DataCompressed) != 0 && _canCompress) { // decompress the data - engine/baseclientstate.cpp (hl2_src) line 1364 int uncompressedSize = bsr.ReadSInt(); int compressedSize = bsr.ReadSInt(); byte[] data = Compression.Decompress(ref bsr, compressedSize - 8); // -8 to ignore header decompressedIndex = DemoRef.DecompressedLookup.Count; DemoRef.DecompressedLookup.Add(data); // so that we can access the reader for the entries later if (data.Length != uncompressedSize) { throw new Exception("could not decompress data in string table update"); } bsr = new BitStreamReader(data); } int entryIndex = -1; var history = new C5.CircularQueue <string>(32); for (int i = 0; i < _numUpdatedEntries; i++) { entryIndex++; if (!bsr.ReadBool()) { entryIndex = (int)bsr.ReadUInt(BitUtils.HighestBitIndex(tableToUpdate.MaxEntries)); } string?entryName = null; if (bsr.ReadBool()) { if (bsr.ReadBool()) // the first part of the string may be the same as for other entries { int index = (int)bsr.ReadUInt(5); int subStrLen = (int)bsr.ReadUInt(SubStringBits); entryName = history[index][..subStrLen];
protected override void Parse(ref BitStreamReader bsr) { if ((DemoParseResult & DemoParseResult.DataTooLong) != 0) { throw new InvalidDataException("data too long"); } // make sure we set the demo settings first Header = new DemoHeader(this); Header.ParseStream(ref bsr); DemoInfo = new DemoInfo(this); // it might be worth it to implement updating helper classes with listeners, but it's not a huge deal atm StringTablesManager = new StringTablesManager(this); ErrorList = new List <string>(); DecompressedLookup = new List <byte[]>(); Frames = new List <PacketFrame>(); StartTick = 0; try { PacketFrame frame; do { frame = new PacketFrame(this); Frames.Add(frame); frame.ParseStream(ref bsr); _parseProgress?.Report((double)bsr.CurrentBitIndex / bsr.BitLength); } while (frame.Type != PacketType.Stop && bsr.BitsRemaining >= 24); // would be 32 but the last byte is often cut off StartAdjustmentTick ??= 0; EndTick = this.FilterForPacket <Packet>().Select(packet => packet.Tick).Where(i => i >= 0).Max(); } catch (Exception e) { _exceptionDuringParsing = true; Debug.WriteLine($"Exception after parsing {Frames.Count - 1} packets"); LogError($"Exception after parsing {Frames.Count - 1} packets: {e.Message}"); throw; } EndAdjustmentTick ??= EndTick; DemoParseResult |= DemoParseResult.Success; }