Skip to content
This repository has been archived by the owner on Mar 30, 2022. It is now read-only.

Commit

Permalink
Parser types are objects rather than ints.
Browse files Browse the repository at this point in the history
- Opens the door for more complex parser types.
  • Loading branch information
pgriess committed Aug 16, 2010
1 parent 03bb3b3 commit bf88bdc
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 97 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -2,5 +2,6 @@

test:
for f in `ls -1 test/test-*.js` ; do \
echo ">>> Testing $$f" ; \
node $$f ; \
done
139 changes: 62 additions & 77 deletions lib/strtok.js
Expand Up @@ -3,51 +3,74 @@
var assert = require('assert');
var Buffer = require('buffer').Buffer;

// Definition for all primitive types; contents are used to generate other
// data structures for easier use
//
// Each type has
//
// - a human-readable name
// - a length
// - an implicit ID (its index in this array)
var TYPETAB = [
{ name : 'DEFER', len : 0 },
{ name : 'DONE', len : 0 },
{ name : 'UINT8_LE', len : 1 },
{ name : 'UINT8_BE', len : 1 },
{ name : 'UINT16_LE', len : 2 },
{ name : 'UINT16_BE', len : 2 },
{ name : 'UINT32_LE', len : 4 },
{ name : 'UINT32_BE', len : 4 }
];

// Map of type names to IDs
var typesMap = (function() {
var m = {};
for (var i = 0; i < TYPETAB.length; i++) {
var t = TYPETAB[i];

m[t.name] = i;
// Sentinel types

var DEFER = {};
exports.DEFER = DEFER;

var DONE = {};
exports.DONE = DONE;

// Primitive types

var UINT8_LE = {
len : 1,
get : function(buf) {
return buf[0];
}
};
exports.UINT8_LE = UINT8_LE;

var UINT8_BE = UINT8_LE;
exports.UINT8_BE = UINT8_BE;

var UINT16_LE = {
len : 2,
get : function(buf) {
return buf[0] | (buf[1] << 8);
}
};
exports.UINT16_LE = UINT16_LE;

var UINT16_BE = {
len : 2,
get : function(buf) {
return (buf[0] << 8) | buf[1];
}
};
exports.UINT16_BE = UINT16_BE;

var UINT32_LE = {
len : 4,
get : function(buf) {
return buf[0] | (buf[1] << 8) |
(buf[2] << 16) | (buf[3] << 24);
}
};
exports.UINT32_LE = UINT32_LE;

return m;
})();
exports.Types = typesMap;
var UINT32_BE = {
len : 4,
get : function(buf) {
return (buf[0] << 24) | (buf[1] << 16) |
(buf[2] << 8) | buf[3];
}
};
exports.UINT32_BE = UINT32_BE;

// Parse a stream
var parse = function(s, cb) {
// Type of data that we're to parse next; if DEFER, we're awaiting
// an invocation of typeCallback
var type = typesMap.DEFER;
var type = DEFER;

// Data that we've seen but not yet processed / handed off to cb; first
// byte for 'type' always at 0
var buf = undefined;

// Callback for FSM to tell us what type to expect next
var typeCallback = function(t) {
if (type !== typesMap.DEFER) {
if (type !== DEFER) {
throw new Error('refusing to overwrite non-DEFER type');
}

Expand All @@ -59,50 +82,14 @@ var parse = function(s, cb) {
// Process data that we have accumulated so far, emitting any type(s)
// collected. This is the main parsing loop.
var emitData = function() {
while (type != typesMap.DONE &&
type != typesMap.DEFER &&
buf.length >= TYPETAB[type].len) {
var v = undefined;

switch (type) {
case typesMap.UINT8_LE:
case typesMap.UINT8_BE:
v = buf[0];
break;

case typesMap.UINT16_LE:
v = buf[0] | (buf[1] << 8);
break;

case typesMap.UINT16_BE:
v = (buf[0] << 8) | buf[1];
break;

case typesMap.UINT32_LE:
v = buf[0] | (buf[1] << 8) |
(buf[2] << 16) | (buf[3] << 24);
break;

case typesMap.UINT32_BE:
v = (buf[0] << 24) | (buf[1] << 16) |
(buf[2] << 8) | buf[3];
break;

default:
console.error('don\'t know how to handle type: ' + type);
// XXX: not handling this correctly
return;
}

buf = buf.slice(TYPETAB[type].len, buf.length);
while (type !== DONE && type !== DEFER && buf.length >= type.len) {
var v = type.get(buf);

buf = buf.slice(type.len, buf.length);
type = cb(v, typeCallback);
if (!(type >= 0 && type < TYPETAB.length)) {
console.error('invalid type returned: ' + type + '; aborting');
type = typesMap.DONE;
}
}

if (type === typesMap.DONE) {
if (type === DONE) {
s.removeListener('data', dataListener);
}
};
Expand All @@ -128,10 +115,8 @@ var parse = function(s, cb) {

// Get the initial type
type = cb(undefined, typeCallback);
if (!(type >= 0 && type < TYPETAB.length)) {
throw new Error('invalid type returned from initial callback');
if (type !== DONE) {
s.on('data', dataListener);
}

s.on('data', dataListener);
};
exports.parse = parse;
10 changes: 5 additions & 5 deletions test/test-defer.js
Expand Up @@ -8,23 +8,23 @@ var seen = 0;

strtok.parse(new TestStream('\x1a\x1a\x1a\x1a\x1a\x1a'), function(v, cb) {
if (v === undefined) {
return strtok.Types.UINT8_LE;
return strtok.UINT8_LE;
}

switch (seen++ % 2) {
case 0:
assert.equal(v, 0x1a);
process.nextTick(function() {
cb((seen < 6) ? strtok.Types.UINT8_BE : strtok.Types.DONE);
cb((seen < 6) ? strtok.UINT8_BE : strtok.DONE);
});
return strtok.Types.DEFER;
return strtok.DEFER;

case 1:
assert.equal(v, 0x1a);
process.nextTick(function() {
cb((seen < 6) ? strtok.Types.UINT8_LE : strtok.Types.DONE);
cb((seen < 6) ? strtok.UINT8_LE : strtok.DONE);
});
return strtok.Types.DEFER;
return strtok.DEFER;
}
});

Expand Down
10 changes: 5 additions & 5 deletions test/test-uint16.js
Expand Up @@ -8,21 +8,21 @@ var seen = 0;

strtok.parse(new TestStream('\x1a\x00\x1a\x00\x1a\x00\x1a\x00'), function(v) {
if (v === undefined) {
return strtok.Types.UINT16_LE;
return strtok.UINT16_LE;
}

switch (seen++ % 2) {
case 0:
assert.equal(v, 0x001a);
return (seen < 4) ?
strtok.Types.UINT16_BE :
strtok.Types.DONE;
strtok.UINT16_BE :
strtok.DONE;

case 1:
assert.equal(v, 0x1a00);
return (seen < 4) ?
strtok.Types.UINT16_LE :
strtok.Types.DONE;
strtok.UINT16_LE :
strtok.DONE;
}
});

Expand Down
10 changes: 5 additions & 5 deletions test/test-uint32.js
Expand Up @@ -8,21 +8,21 @@ var seen = 0;

strtok.parse(new TestStream('\x1a\x00\x1a\x00\x1a\x00\x1a\x00\x1a\x00\x1a\x00\x1a\x00\x1a\x00'), function(v) {
if (v === undefined) {
return strtok.Types.UINT32_LE;
return strtok.UINT32_LE;
}

switch (seen++ % 2) {
case 0:
assert.equal(v, 0x001a001a);
return (seen < 4) ?
strtok.Types.UINT32_BE :
strtok.Types.DONE;
strtok.UINT32_BE :
strtok.DONE;

case 1:
assert.equal(v, 0x1a001a00);
return (seen < 4) ?
strtok.Types.UINT32_LE :
strtok.Types.DONE;
strtok.UINT32_LE :
strtok.DONE;
}
});

Expand Down
10 changes: 5 additions & 5 deletions test/test-uint8.js
Expand Up @@ -9,21 +9,21 @@ var seen = 0;

strtok.parse(new TestStream('\x1a\x1a\x1a\x1a\x1a\x1a'), function(v) {
if (v === undefined) {
return strtok.Types.UINT8_LE;
return strtok.UINT8_LE;
}

switch (seen++ % 2) {
case 0:
assert.equal(v, 0x1a);
return (seen < 6) ?
strtok.Types.UINT8_BE :
strtok.Types.DONE;
strtok.UINT8_BE :
strtok.DONE;

case 1:
assert.equal(v, 0x1a);
return (seen < 6) ?
strtok.Types.UINT8_LE :
strtok.Types.DONE;
strtok.UINT8_LE :
strtok.DONE;
}
});

Expand Down

0 comments on commit bf88bdc

Please sign in to comment.