mirror of
https://github.com/demostf/demo.js
synced 2026-06-03 16:44:12 +02:00
node stream parsing wip
This commit is contained in:
parent
ec63085fba
commit
e88cd0cd7e
5 changed files with 127 additions and 13 deletions
90
StreamParser.js
Normal file
90
StreamParser.js
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
var util = require('util');
|
||||
var Parser = require('./parser');
|
||||
var State = require('./state');
|
||||
var BitStream = require('bit-buffer').BitStream;
|
||||
|
||||
var StreamParser = function (stream) {
|
||||
this.stream = stream;
|
||||
this.state = new State();
|
||||
this.on('packet', this.state.updateState.bind(this.state));
|
||||
this.header = null;
|
||||
this.buffer = new Buffer(0);
|
||||
};
|
||||
|
||||
util.inherits(StreamParser, Parser);
|
||||
|
||||
function shrinkBuffer(buffer, length) {
|
||||
if (length < 0) {
|
||||
throw 'cant shrink by negative length ' + length;
|
||||
}
|
||||
return buffer.slice(length, buffer.length);
|
||||
}
|
||||
|
||||
StreamParser.prototype.eatBuffer = function (length) {
|
||||
this.buffer = shrinkBuffer(this.buffer, length);
|
||||
};
|
||||
|
||||
StreamParser.prototype.start = function () {
|
||||
this.stream.on('data', this.handleData.bind(this));
|
||||
this.stream.on('end', function () {
|
||||
this.emit('done', this.state.get());
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
StreamParser.prototype.handleData = function (data) {
|
||||
this.buffer = Buffer.concat([this.buffer, data]);
|
||||
if (this.header === null) {
|
||||
if (this.buffer.length > 1072) {
|
||||
this.header = this.parseHeader(new BitStream(this.buffer));
|
||||
this.eatBuffer(1072);
|
||||
}
|
||||
} else {
|
||||
this.readMessage();
|
||||
}
|
||||
};
|
||||
|
||||
StreamParser.prototype.readMessage = function () {
|
||||
if (this.buffer.length < 9) { // 9 byte minimum message header (type, tick, length)
|
||||
return;
|
||||
}
|
||||
var stream = new BitStream(this.buffer);
|
||||
var type = stream.readBits(8);
|
||||
if (type === Parser.MessageType.Stop) {
|
||||
console.log('stop');
|
||||
return;
|
||||
}
|
||||
var tick = stream.readInt32();
|
||||
|
||||
var headerSize = 5;
|
||||
var extraHeader = 0;
|
||||
|
||||
switch (type) {
|
||||
case Parser.MessageType.Sigon:
|
||||
case Parser.MessageType.Packet:
|
||||
extraHeader += 0x54; // command/sequence info
|
||||
break;
|
||||
case Parser.MessageType.UserCmd:
|
||||
extraHeader += 0x04; // unknown / outgoing sequence
|
||||
break;
|
||||
case Parser.MessageType.Stop:
|
||||
case Parser.MessageType.SyncTick:
|
||||
this.eatBuffer(headerSize);
|
||||
return;
|
||||
}
|
||||
stream.byteIndex += extraHeader;
|
||||
var length = stream.readInt32();
|
||||
headerSize += extraHeader + 4;
|
||||
|
||||
if (this.buffer.length < (headerSize + length)) {
|
||||
console.log('wants ' + length);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('got message ' + tick);
|
||||
var messageBuffer = this.buffer.slice(headerSize, headerSize + length);
|
||||
this.eatBuffer(headerSize + length);
|
||||
var message = this.parseMessage(messageBuffer, type, tick, length);
|
||||
this.handleMessage(message);
|
||||
};
|
||||
|
||||
module.exports = StreamParser;
|
||||
|
|
@ -12,6 +12,15 @@ var echo = function (data) {
|
|||
console.log(string);
|
||||
};
|
||||
|
||||
//var stream = fs.createReadStream(argv._[0]);
|
||||
//
|
||||
//var demo = Demo.fromNodeStream(stream);
|
||||
//var parser = demo.getParser();
|
||||
//parser.on('done', function (state) {
|
||||
// echo(state);
|
||||
//});
|
||||
//parser.start();
|
||||
|
||||
fs.readFile(argv._[0], function (err, data) {
|
||||
if (err) throw err;
|
||||
var demo = Demo.fromNodeBuffer(data);
|
||||
|
|
|
|||
13
demo.js
13
demo.js
|
|
@ -1,5 +1,6 @@
|
|||
var BitStream = require('bit-buffer').BitStream;
|
||||
var Parser = require('./parser');
|
||||
var StreamParser = require('./StreamParser');
|
||||
|
||||
var Demo = function (arrayBuffer) {
|
||||
this.stream = new BitStream(arrayBuffer);
|
||||
|
|
@ -9,6 +10,14 @@ Demo.prototype.getParser = function () {
|
|||
return new Parser(this.stream);
|
||||
};
|
||||
|
||||
var StreamDemo = function (nodeStream) {
|
||||
this.stream = nodeStream;
|
||||
};
|
||||
|
||||
StreamDemo.prototype.getParser = function () {
|
||||
return new StreamParser(this.stream);
|
||||
};
|
||||
|
||||
Demo.fromNodeBuffer = function (nodeBuffer) {
|
||||
var arrayBuffer = new ArrayBuffer(nodeBuffer.length);
|
||||
var view = new Uint8Array(arrayBuffer);
|
||||
|
|
@ -18,6 +27,10 @@ Demo.fromNodeBuffer = function (nodeBuffer) {
|
|||
return new Demo(arrayBuffer);
|
||||
};
|
||||
|
||||
Demo.fromNodeStream = function (nodeStream) {
|
||||
return new StreamDemo(nodeStream);
|
||||
};
|
||||
|
||||
Demo.fromPath = function (path) {
|
||||
var arrayBuffer = new ArrayBuffer(nodeBuffer.length);
|
||||
var view = new Uint8Array(arrayBuffer);
|
||||
|
|
|
|||
23
package.json
23
package.json
|
|
@ -1,13 +1,14 @@
|
|||
{
|
||||
"name": "tf2-demo",
|
||||
"description": "A parser for TF2 demo files",
|
||||
"version": "0.1.0",
|
||||
"bin": {
|
||||
"demo-analyse": "./bin/analyse.js"
|
||||
},
|
||||
"main": "demo.js",
|
||||
"dependencies": {
|
||||
"bit-buffer": "icewind1991/bit-buffer",
|
||||
"minimist": "1.1.x"
|
||||
}
|
||||
"name": "tf2-demo",
|
||||
"description": "A parser for TF2 demo files",
|
||||
"version": "0.1.0",
|
||||
"bin": {
|
||||
"demo-analyse": "./bin/analyse.js"
|
||||
},
|
||||
"main": "demo.js",
|
||||
"dependencies": {
|
||||
"bit-buffer": "icewind1991/bit-buffer",
|
||||
"minimist": "1.1.x",
|
||||
"smart-buffer": "^1.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ var DataTable = require('./datatable');
|
|||
var BitStream = require('bit-buffer').BitStream;
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
var Parser = function (steam) {
|
||||
this.stream = steam;
|
||||
var Parser = function (stream) {
|
||||
this.stream = stream;
|
||||
this.state = new State();
|
||||
this.packets = [];
|
||||
this.strings = {};
|
||||
|
|
@ -57,6 +57,7 @@ Parser.prototype.parseBody = function () {
|
|||
this.handleMessage(message);
|
||||
}
|
||||
this.strings = StringTable.tables;
|
||||
this.emit('done', this.state.get());
|
||||
return this.state.get();
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue