por
Version:
A streaming parser for the SPSS / PSPP Portable File Format (.por).
88 lines (75 loc) • 2.43 kB
JavaScript
var CODE_LINE_FEED = "\n".charCodeAt(0),
CODE_CARRIAGE_RETURN = "\r".charCodeAt(0);
var STATES = 0,
STATE_DEFAULT = ++STATES,
STATE_MAYBE_LINE = ++STATES,
STATE_AFTER_LINE = ++STATES;
// Parses a .por file into 80-byte lines, separated by \r\n.
module.exports = function() {
var parser = {
push: parser_push,
pop: parser_pop
},
buffer = new Buffer(0),
bufferOffset = 0,
bufferLength = 0,
state = STATE_DEFAULT,
fragment = null;
function parser_push(data) {
if (bufferOffset < bufferLength) throw new Error("cannot push before all lines are popped");
bufferLength = data.length;
bufferOffset = 0;
buffer = data;
}
function parser_pop() {
var oldBufferOffset = bufferOffset;
// Find the next line terminator.
while (bufferOffset < bufferLength) {
var code = buffer[bufferOffset++];
if (state === STATE_MAYBE_LINE) {
if (code === CODE_LINE_FEED) {
state = STATE_AFTER_LINE;
break;
}
state = STATE_DEFAULT; // ignore bare \r
}
if (code === CODE_LINE_FEED) {
state = STATE_AFTER_LINE_FEED;
break;
}
if (code === CODE_CARRIAGE_RETURN) {
state = STATE_MAYBE_LINE;
continue;
}
}
// Slice out the new data.
var newFragment = buffer.slice(oldBufferOffset, bufferOffset);
// Combine it with the old data, if any.
if (fragment != null) {
var oldFragment = newFragment;
newFragment = new Buffer(fragment.length + oldFragment.length);
fragment.copy(newFragment);
oldFragment.copy(newFragment, fragment.length);
fragment = null;
}
// We read a line! Slice off the \r\n.
if (state === STATE_AFTER_LINE) {
state = STATE_DEFAULT;
newFragment = newFragment.slice(0, -2)
// Pad the line with spaces, if not 80 characters.
if (newFragment.length < 80) {
var oldFragment = newFragment;
newFragment = new Buffer(80);
oldFragment.copy(newFragment);
newFragment.fill(32, oldFragment.length);
}
return newFragment;
}
// Otherwise, we’ve read part of a line. Copy the fragment so that the
// source buffer can be modified without changing the fragment contents.
fragment = new Buffer(newFragment.length);
newFragment.copy(fragment);
return null;
}
return parser;
};