It's actually more of a recording of the net packets that were sent.
You can poke around the code in and around
here. Especially DemoReader.cpp should give you an idea (it reads a netcode::RawPacket when requested, which is simply stored/zipped as the memory block that would be in the program). To read those packets, you need to know how the
chunk headers look (because they tell you how much data to read).
Once you figured out how to read the data in meaningful chunks, you'll have to look into how a RawPacket is decoded/interpreted in the engine to make sense of that data.
TL;DR: There is no line separator. It's binary data.