private void GenerateThread()
        {
            parser = new SourceDemoParser((SourceDemo)demo);

            parser.AddMessageHandler((Byte)SourceDemoParser.MessageId.SVC_CreateStringTable, MessageCreateStringTable);
            parser.AddMessageHandler((Byte)SourceDemoParser.MessageId.SVC_UpdateStringTable, MessageUpdateStringTable);
            parser.AddMessageHandler((Byte)SourceDemoParser.MessageId.SVC_UserMessage, MessageUserMessage);
            parser.AddMessageHandler((Byte)SourceDemoParser.MessageId.SVC_GameEventList, MessageGameEventList);

            parser.Open();
            parser.Seek(SourceDemo.HeaderSizeInBytes);

            // so we can detect when signon frames stop and packet frames start
            SourceDemoParser.FrameType lastFrameType = SourceDemoParser.FrameType.Signon;

            Int32 percentRead = 0;

            try
            {
                while (true)
                {
                    SourceDemoParser.FrameType frameType = parser.ReadFrameHeader().Type;

                    if (frameType == SourceDemoParser.FrameType.Stop)
                    {
                        progressWindowInterface.UpdateProgress(100);
                        break;
                    }
                    else if (frameType == SourceDemoParser.FrameType.Signon || frameType == SourceDemoParser.FrameType.Packet)
                    {
                        if (lastFrameType == SourceDemoParser.FrameType.Signon && frameType == SourceDemoParser.FrameType.Packet)
                        {
                            parser.AddMessageHandler((Byte)SourceDemoParser.MessageId.NET_Tick, MessageNetTick);
                        }

                        lastFrameType = frameType;

                        parser.ReadCommandInfo();
                        parser.ReadSequenceInfo();

                        Int32 frameLength = parser.Reader.ReadInt32();

                        try
                        {
                            parser.ParsePacketMessages(frameLength);
                        }
                        catch (ThreadAbortException)
                        {
                            throw;
                        }
                        catch (Exception ex)
                        {
                            throw new ApplicationException("Message parsing error.\n\n" + parser.ComputeMessageLog(), ex);
                        }
                    }
                    else
                    {
                        parser.ParseFrame(frameType);
                    }

                    // calculate what percent of the file has been read
                    Int32 oldPercentRead = percentRead;

                    percentRead = (Int32)(parser.Position / (Single)parser.FileLength * 100.0f);

                    if (percentRead != oldPercentRead)
                    {
                        progressWindowInterface.UpdateProgress(percentRead);
                    }
                }
            }
            finally
            {
                parser.Close();
            }
        }