Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

binary-parser

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

binary-parser - npm Package Compare versions

Comparing version 0.0.1 to 0.0.2

263

lib/binary_parser.js
//========================================================================================
// Globals
//========================================================================================
var util = require('util');
var Parser = function() {
this.varName = '';
this.type = '';
this.options = {};
this.next = null;
this.head = null;
this.compiled = null;
};
var PRIMITIVE_TYPES = {

@@ -34,2 +24,3 @@ 'UInt8' : 1,

'String' : null,
'Buffer' : null,
'Array' : null,

@@ -49,24 +40,24 @@ 'Skip' : null,

//========================================================================================
// Parser builder functions
// class Parser
//========================================================================================
Parser.start = function() {
return new Parser();
//----------------------------------------------------------------------------------------
// constructor
//----------------------------------------------------------------------------------------
var Parser = function() {
this.varName = '';
this.type = '';
this.options = {};
this.next = null;
this.head = null;
this.compiled = null;
};
Parser.prototype.setNextParser = function(type, varName, options) {
var parser = new Parser();
parser.type = NAME_MAP[type];
parser.varName = varName;
parser.options = options || parser.options;
if (this.head) {
this.head.next = parser;
} else {
this.next = parser;
}
this.head = parser;
//----------------------------------------------------------------------------------------
// public methods
//----------------------------------------------------------------------------------------
return this;
Parser.start = function() {
return new Parser();
};

@@ -98,2 +89,10 @@

Parser.prototype.buffer = function(varName, options) {
if (!options.length && !options.readUntil) {
throw new Error('Length nor readUntil is defined in buffer parser');
}
return this.setNextParser('buffer', varName, options);
};
Parser.prototype.array = function(varName, options) {

@@ -153,68 +152,84 @@ if (!options.readUntil && !options.length) {

//========================================================================================
// Parser
//========================================================================================
Parser.prototype.getCode = function() {
var ctx = new Context();
// Follow the parser chain till the root and start parsing from there
Parser.prototype.parse = function(buffer) {
if (!Buffer.isBuffer(buffer)) {
throw new Error('argument "buffer" is not a Buffer object');
}
ctx.pushCode('var vars = {};');
ctx.pushCode('var iterator = 0;');
this.generate(ctx);
ctx.pushCode('return vars;');
if (!this.compiled) {
this.compile();
}
return this.compiled(buffer);
return ctx.code;
};
var Context = function() {
this.code = '';
this.scopes = [];
Parser.prototype.compile = function() {
this.compiled = new Function('buffer', this.getCode());
};
Context.prototype.generateVariable = function(name) {
var arr = ['vars'];
Array.prototype.push.apply(arr, this.scopes);
if (name) {
arr.push(name);
Parser.prototype.sizeOf = function() {
var size = NaN;
if (Object.keys(PRIMITIVE_TYPES).indexOf(this.type) >= 0) {
size = PRIMITIVE_TYPES[this.type];
// if this is a fixed length string
} else if (this.type === 'String' && typeof this.options.length === 'number') {
size = this.options.length;
// if this is a fixed length array
} else if (this.type === 'Array' && typeof this.options.length === 'number') {
var elementSize = NaN;
if (typeof this.options.type === 'string'){
elementSize = PRIMITIVE_TYPES[NAME_MAP[this.options.type]];
} else if (this.options.type instanceof Parser) {
elementSize = this.options.type.sizeOf();
}
size = this.options.length * elementSize;
// if this a skip
} else if (this.type === 'Skip') {
size = this.options.length;
} else if (!this.type) {
size = 0;
}
return arr.join('.');
if (this.next) {
size += this.next.sizeOf();
}
return size;
};
Context.prototype.generateOption = function(val) {
if (typeof val === 'number') {
return val.toString();
} else if (typeof val === 'string') {
return this.generateVariable(val);
} else if (typeof val === 'function') {
return util.format('(%s).call(%s)', val, this.generateVariable());
// Follow the parser chain till the root and start parsing from there
Parser.prototype.parse = function(buffer) {
if (!Buffer.isBuffer(buffer)) {
throw new Error('argument "buffer" is not a Buffer object');
}
};
Context.prototype.pushCode = function(code) {
var re = /{\d+}/g;
var matches = code.match(re);
var params = Array.prototype.slice.call(arguments, 1);
if (matches) {
matches.forEach(function(match) {
var index = parseInt(match.substr(1, match.length - 2), 10);
code = code.replace(match, params[index].toString());
});
if (!this.compiled) {
this.compile();
}
this.code += code + '\n';
return this.compiled(buffer);
};
Parser.prototype.compile = function() {
var ctx = new Context();
//----------------------------------------------------------------------------------------
// private methods
//----------------------------------------------------------------------------------------
ctx.pushCode('var vars = {};');
ctx.pushCode('var iterator = 0;');
this.generate(ctx);
ctx.pushCode('return vars;');
Parser.prototype.setNextParser = function(type, varName, options) {
var parser = new Parser();
parser.type = NAME_MAP[type];
parser.varName = varName;
parser.options = options || parser.options;
if (this.head) {
this.head.next = parser;
} else {
this.next = parser;
}
this.head = parser;
this.compiled = new Function('buffer', ctx.code);
return this;
};

@@ -283,2 +298,22 @@

Parser.prototype.generateBuffer = function(ctx) {
if (this.options.readUntil === 'eof') {
ctx.pushCode('{0} = buffer.slice(iterator, buffer.length - 1);',
ctx.generateVariable(this.varName)
);
} else {
ctx.pushCode('{0} = buffer.slice(iterator, iterator + {1});',
ctx.generateVariable(this.varName),
ctx.generateOption(this.options.length)
);
ctx.pushCode('iterator += {0};', ctx.generateOption(this.options.length));
}
if (this.options.clone) {
ctx.pushCode('{0} = (function() { var buf = new Buffer({0}.length); {0}.copy(buf); return buf; })();',
ctx.generateVariable(this.varName)
);
}
};
Parser.prototype.generateArray = function(ctx) {

@@ -321,13 +356,2 @@ var length = ctx.generateOption(this.options.length);

Parser.prototype.generateChoiceCase = function(ctx, varName, type) {
if (typeof type === 'string') {
ctx.pushCode('{0} = buffer.read{1}(iterator);', ctx.generateVariable(this.varName), NAME_MAP[type]);
ctx.pushCode('iterator += {0};', PRIMITIVE_TYPES[NAME_MAP[type]]);
} else if (type instanceof Parser) {
ctx.scopes.push(varName);
type.generate(ctx);
ctx.scopes.pop();
}
};
Parser.prototype.generateChoice = function(ctx) {

@@ -358,35 +382,48 @@ var tag = ctx.generateOption(this.options.tag);

Parser.prototype.sizeOf = function() {
var size = NaN;
//----------------------------------------------------------------------------------------
// constructor
//----------------------------------------------------------------------------------------
if (Object.keys(PRIMITIVE_TYPES).indexOf(this.type) >= 0) {
size = PRIMITIVE_TYPES[this.type];
// if this is a fixed length string
} else if (this.type === 'String' && typeof this.options.length === 'number') {
size = this.options.length;
// if this is a fixed length array
} else if (this.type === 'Array' && typeof this.options.length === 'number') {
var elementSize = NaN;
if (typeof this.options.type === 'string'){
elementSize = PRIMITIVE_TYPES[NAME_MAP[this.options.type]];
} else if (this.options.type instanceof Parser) {
elementSize = this.options.type.sizeOf();
}
size = this.options.length * elementSize;
// if this a skip
} else if (this.type === 'Skip') {
size = this.options.length;
var Context = function() {
this.code = '';
this.scopes = [];
};
} else if (!this.type) {
size = 0;
//----------------------------------------------------------------------------------------
// public methods
//----------------------------------------------------------------------------------------
Context.prototype.generateVariable = function(name) {
var arr = ['vars'];
Array.prototype.push.apply(arr, this.scopes);
if (name) {
arr.push(name);
}
if (this.next) {
size += this.next.sizeOf();
return arr.join('.');
};
Context.prototype.generateOption = function(val) {
if (typeof val === 'number') {
return val.toString();
} else if (typeof val === 'string') {
return this.generateVariable(val);
} else if (typeof val === 'function') {
return '(' + val + ').call(' + this.generateVariable() + ')';
}
};
return size;
Context.prototype.pushCode = function(code) {
var re = /{\d+}/g;
var matches = code.match(re);
var params = Array.prototype.slice.call(arguments, 1);
if (matches) {
matches.forEach(function(match) {
var index = parseInt(match.substr(1, match.length - 2), 10);
code = code.replace(match, params[index].toString());
});
}
this.code += code + '\n';
};

@@ -393,0 +430,0 @@

{
"name": "binary-parser",
"version": "0.0.1",
"version": "0.0.2",
"description": "Blazing-fast binary parser builder",

@@ -5,0 +5,0 @@ "main": "lib/binary_parser.js",

@@ -82,3 +82,3 @@ # Binary-parser

are valid. See [`Buffer.toString`](http://nodejs.org/api/buffer.html#buffer_buf_tostring_encoding_start_end) for more info.
- `length `- (Required) Length of the string. Can be a number, string or a function.
- `length ` - (Required) Length of the string. Can be a number, string or a function.
Use number for statically sized arrays, string to reference another variable and

@@ -88,2 +88,16 @@ function to do some calculation.

### buffer(name [,options])
Parse bytes as a string. `name` should consist only of alpha numeric characters and start
with an alphabet. `options` is an object; following options are available:
- `clone` - (Optional, defaults to `false`) By default, `buffer(name [,options])` returns a new buffer which references
the same memory as the parser input, but offset and cropped by a certain range. If this option is true, input buffer
will be cloned and a new buffer referncing another memory is returned.
- `length ` - (either `length` or `readUntil` is required) Length of the buffer. Can be a number, string or a function.
Use number for statically sized buffers, string to reference another variable and
function to do some calculation.
- `readUntil` - (either `length` or `readUntil` is required) If `'eof'`, then this parser
will read till it reaches end of the `Buffer` object.
### array(name [,options])

@@ -177,2 +191,6 @@ Parse bytes as an array. `options` is an object; following options are available:

### getCode()
Dynamically generates the code for this parser and returns it as a string.
Usually used for debugging.
### Assertion

@@ -179,0 +197,0 @@ You can do assertions during the parsing (useful for checking magic numbers and so on).

@@ -83,2 +83,31 @@ var assert = require('assert');

describe('Buffer parser', function() {
it('should parse as buffer', function() {
var parser = new Parser()
.uint8('len')
.buffer('raw', {
length: 'len'
});
var buf = new Buffer('deadbeefdeadbeef', 'hex');
var result = parser.parse(Buffer.concat([new Buffer([8]), buf]));
assert.deepEqual(result.raw, buf);
});
it('should clone buffer if options.clone is true', function() {
var parser = new Parser()
.buffer('raw', {
length: 8,
clone: true
});
var buf = new Buffer('deadbeefdeadbeef', 'hex');
var result = parser.parse(buf);
assert.deepEqual(result.raw, buf);
result.raw[0] = 0xff;
assert.notDeepEqual(result.raw, buf);
});
});
describe('Array parser', function() {

@@ -85,0 +114,0 @@ it('should parse array of primitive types', function(){

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc