cbor
Version:
Encode and parse CBOR documents.
254 lines (214 loc) • 7.51 kB
JavaScript
(function() {
var BufferStream, DEFAULT_TAG_FUNCS, Decoder, Evented, MINUS_ONE, MT, TAG, TEN, TWO, Tagged, bignumber, f, k, stream, url, utils, v, _ref,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
stream = require('stream');
url = require('url');
bignumber = require('bignumber.js');
BufferStream = require('./BufferStream');
Tagged = require('./tagged');
utils = require('./utils');
Evented = require('./evented');
_ref = require('./constants'), TAG = _ref.TAG, MT = _ref.MT;
MINUS_ONE = new bignumber(-1);
TEN = new bignumber(10);
TWO = new bignumber(2);
DEFAULT_TAG_FUNCS = {};
module.exports = Decoder = (function(_super) {
__extends(Decoder, _super);
function Decoder(options) {
this.options = options != null ? options : {};
this._on_end = __bind(this._on_end, this);
this._on_stream_stop = __bind(this._on_stream_stop, this);
this._on_stream_start = __bind(this._on_stream_start, this);
this._on_map_stop = __bind(this._on_map_stop, this);
this._on_map_start = __bind(this._on_map_start, this);
this._on_array_stop = __bind(this._on_array_stop, this);
this._on_array_start = __bind(this._on_array_start, this);
this._on_value = __bind(this._on_value, this);
this._on_error = __bind(this._on_error, this);
Decoder.__super__.constructor.call(this);
this.tags = utils.extend({}, DEFAULT_TAG_FUNCS, this.options.tags);
this.stack = [];
this.parser = new Evented({
input: this.options.input
});
this.parser.on('value', this._on_value);
this.parser.on('array-start', this._on_array_start);
this.parser.on('array-stop', this._on_array_stop);
this.parser.on('map-start', this._on_map_start);
this.parser.on('map-stop', this._on_map_stop);
this.parser.on('stream-start', this._on_stream_start);
this.parser.on('stream-stop', this._on_stream_stop);
this.parser.on('end', this._on_end);
this.parser.on('error', this._on_error);
this.on('finish', function() {
return this.parser.end();
});
}
Decoder.prototype.start = function() {
return this.parser.start();
};
Decoder.prototype._on_error = function(er) {
return this.emit('error', er);
};
Decoder.prototype._process = function(val, tags, kind) {
var er, f, key, t, _i, _ref1;
for (_i = tags.length - 1; _i >= 0; _i += -1) {
t = tags[_i];
try {
f = this.tags[t];
if (f != null) {
val = (_ref1 = f.call(this, val)) != null ? _ref1 : new Tagged(t, val);
} else {
val = new Tagged(t, val);
}
} catch (_error) {
er = _error;
val = new Tagged(t, val, er);
}
}
switch (kind) {
case null:
return this.emit('complete', val);
case 'array-first':
case 'array':
return this.last.push(val);
case 'key-first':
case 'key':
return this.stack.push(val);
case 'stream-first':
case 'stream':
switch (this.mt) {
case MT.BYTE_STRING:
if (!Buffer.isBuffer(val)) {
this.parser.error(new Error('Bad input in stream, expected buffer'));
return;
}
break;
case MT.UTF8_STRING:
if (typeof val !== 'string') {
this.parser.error(new Error('Bad input in stream, expected string'));
return;
}
break;
default:
// istanbul ignore next;
throw new Error('Unknown stream type');
}
return this.last.write(val);
case 'value':
key = this.stack.pop();
this.last[key] = val;
return // istanbul ignore next;
default:
return this.parser.error(new Error("Unknown event kind: " + kind));
}
};
Decoder.prototype._on_value = function(val, tags, kind) {
return this._process(val, tags, kind);
};
Decoder.prototype._on_array_start = function(count, tags, kind) {
if (this.last != null) {
this.stack.push(this.last);
}
return this.last = [];
};
Decoder.prototype._on_array_stop = function(count, tags, kind) {
var val, _ref1;
_ref1 = [this.last, this.stack.pop()], val = _ref1[0], this.last = _ref1[1];
return this._process(val, tags, kind);
};
Decoder.prototype._on_map_start = function(count, tags, kind) {
if (this.last != null) {
this.stack.push(this.last);
}
return this.last = {};
};
Decoder.prototype._on_map_stop = function(count, tags, kind) {
var val, _ref1;
_ref1 = [this.last, this.stack.pop()], val = _ref1[0], this.last = _ref1[1];
return this._process(val, tags, kind);
};
Decoder.prototype._on_stream_start = function(mt, tags, kind) {
if (this.last != null) {
this.stack.push([this.last, this.mt]);
}
this.mt = mt;
return this.last = new BufferStream;
};
Decoder.prototype._on_stream_stop = function(count, mt, tags, kind) {
var lm, val;
val = this.last.read();
lm = this.stack.pop();
if (lm) {
this.last = lm[0], this.mt = lm[1];
}
if (mt === MT.UTF8_STRING) {
val = val.toString('utf8');
}
return this._process(val, tags, kind);
};
Decoder.prototype._on_end = function() {
return this.emit('end');
};
Decoder.prototype._write = function(buf, offset, encoding) {
return this.parser.write(buf, offset, encoding);
};
Decoder.decode = function(buf, cb) {
var actual, d;
if (cb == null) {
throw new Error("cb must be specified");
}
d = new Decoder({
input: buf
});
actual = [];
d.on('complete', function(v) {
return actual.push(v);
});
d.on('end', function() {
return cb(null, actual);
});
d.on('error', cb);
return d.start();
};
Decoder._tag_DATE_STRING = function(val) {
return new Date(val);
};
Decoder._tag_DATE_EPOCH = function(val) {
return new Date(val * 1000);
};
Decoder._tag_POS_BIGINT = function(val) {
return utils.bufferToBignumber(val);
};
Decoder._tag_NEG_BIGINT = function(val) {
return MINUS_ONE.minus(utils.bufferToBignumber(val));
};
Decoder._tag_DECIMAL_FRAC = function(val) {
var e, m;
e = val[0], m = val[1];
return TEN.pow(e).times(m);
};
Decoder._tag_BIGFLOAT = function(val) {
var e, m;
e = val[0], m = val[1];
return TWO.pow(e).times(m);
};
Decoder._tag_URI = function(val) {
return url.parse(val);
};
Decoder._tag_REGEXP = function(val) {
return new RegExp(val);
};
return Decoder;
})(stream.Writable);
for (k in TAG) {
v = TAG[k];
f = Decoder["_tag_" + k];
if (typeof f === 'function') {
DEFAULT_TAG_FUNCS[v] = f;
}
}
}).call(this);