1
0

735 Zeilen
39 KiB
JavaScript

var fs = require('fs');
var MIB = function (dir) {
return ({
directory: dir ? dir : '',
SymbolBuffer: {},
StringBuffer: '',
Modules: {},
Objects: {},
MACROS: [],
CurrentObject: null,
TempObject: {},
CurrentClause: '',
WaitFor: '',
CharBuffer: {
logit: false,
lastChar: '',
state: '',
open: false,
CurrentSymbol: '',
nested: 0,
isComment: false,
isEqual: false,
isOID: false,
isList: false,
isString: false,
inComment: false,
inGroup: 0,
builder: '',
Table: {},
ColumnIndex: 0,
RowIndex: 0,
ModuleName: {},
PreviousRow: 0,
Append: function (char) {
this.builder += char;
},
Fill: function (FileName, row, column) {
if (this.builder.length == 0) {
return;
}
column = (column - this.builder.length);
var symbol = this.builder.toString().trim();
this.builder = "";
this.builder.length = 0;
if (!this.Table[FileName]) {
this.Table[FileName] = [];
}
if (row == 0) {
this.RowIndex = 0;
this.PreviousRow = 0;
}
if (this.PreviousRow < row) {
this.RowIndex++;
this.ColumnIndex = 0;
this.PreviousRow = row;
}
var R = this.RowIndex;
var C = this.ColumnIndex;
if (!this.Table[FileName][R]) {
this.Table[FileName][R] = [];
}
this.isEqual = false;
switch (symbol) {
case ')':
this.Table[FileName][R][C] = symbol;
this.ColumnIndex++;
this.logit = false;
break;
case '(':
this.Table[FileName][R][C] = symbol;
this.ColumnIndex++;
this.logit = true;
break;
case 'DEFINITIONS':
if (C == 0) {
this.ModuleName[FileName] = this.Table[FileName][R - 1][C];
} else {
this.ModuleName[FileName] = this.Table[FileName][R][C - 1];
}
this.Table[FileName][R][C] = symbol;
this.ColumnIndex++;
break;
case '::=':
this.Table[FileName][R][C] = symbol;
this.ColumnIndex++;
this.isEqual = true;
break;
case '{':
if (this.Table[FileName][R][C - 1] != '::=') {
this.isList = true;
}
this.Table[FileName][R][C] = symbol;
this.ColumnIndex++;
break;
case 'NOTATION':
if (this.Table[FileName][R][C - 1] == 'TYPE' || this.Table[FileName][R][C - 1] == 'VALUE') {
this.Table[FileName][R][C - 1] += ' NOTATION';
}
break;
case 'OF':
if (this.Table[FileName][R][C - 1] == 'SEQUENCE') {
this.Table[FileName][R][C - 1] = 'SEQUENCE OF';
}
break;
case 'IDENTIFIER':
if (this.Table[FileName][R][C - 1] == 'OBJECT') {
this.Table[FileName][R][C - 1] = 'OBJECT IDENTIFIER';
}
break;
case 'STRING':
if (this.Table[FileName][R][C - 1] == 'OCTET') {
this.Table[FileName][R][C - 1] = 'OCTET STRING';
}
break;
default:
this.Table[FileName][R][C] = symbol;
this.ColumnIndex++;
break;
}
}
},
Import: function (FileName) {
this.ParseModule(FileName.split('/')[FileName.split('/').length - 1].split('.')[0], fs.readFileSync(FileName).toString());
},
ParseModule: function (FileName, Contents) {
this.CharBuffer.RowIndex = 0;
this.CharBuffer.ColumnIndex = 0;
var lines = Contents.split('\n');
var line = '';
var i = 0;
while ((line = lines[i]) != null && i <= lines.length) {
this.ParseLine(FileName, line, i);
i++;
}
},
ParseLine: function (FileName, line, row) {
line = line + "\n";
for (var i = 0; i < line.length; i++) {
var char = line.charAt(i);
this.ParseChar(FileName, char, row, i);
}
},
ParseChar: function (FileName, char, row, column) {
switch (char) {
case '\r':
case '\n':
if (!this.CharBuffer.isString) {
this.CharBuffer.Fill(FileName, row, column);
this.CharBuffer.isComment = false;
this.CharBuffer.inGroup = 0; //IGNORE GROUPINGS ACROSS COMMENTS
} else if (this.CharBuffer.isString && this.CharBuffer.isComment) {
this.CharBuffer.Append(char);
}
break;
case '{':
if (this.CharBuffer.isEqual) { this.CharBuffer.isOID = true; }
case '[':
case '(':
if ( ! this.CharBuffer.isString ) {
this.CharBuffer.nested++;
if ( char == '(') {
this.CharBuffer.inGroup++;
}
}
if (this.CharBuffer.builder == 'INTEGER') {
this.CharBuffer.Fill(FileName, row, column);
this.CharBuffer.Append(char);
} else if (this.CharBuffer.isComment || ((this.CharBuffer.isOID || this.CharBuffer.nested > 0) && (!this.CharBuffer.isList || this.CharBuffer.inGroup > 0))) {
this.CharBuffer.Append(char);
} else {
this.CharBuffer.Fill(FileName, row, column);
this.CharBuffer.Append(char);
this.CharBuffer.Fill(FileName, row, column);
}
break;
case '}':
case ']':
case ')':
if ( ! this.CharBuffer.isString ) {
this.CharBuffer.nested--;
if (this.CharBuffer.nested < 0) {
this.CharBuffer.nested = 0;
}
if ( char == ')') {
this.CharBuffer.inGroup--;
if (this.CharBuffer.inGroup < 0) {
this.CharBuffer.inGroup = 0; // ignore grouping across comments
}
}
}
if (this.CharBuffer.isComment || ((this.CharBuffer.isOID || this.CharBuffer.nested >= 0) && (!this.CharBuffer.isList || this.CharBuffer.inGroup >= 0))) {
this.CharBuffer.Append(char);
} else {
this.CharBuffer.Fill(FileName, row, column);
this.CharBuffer.Append(char);
this.CharBuffer.Fill(FileName, row, column);
}
if (char == '}') {
this.CharBuffer.isOID = false;
this.CharBuffer.isList = false;
}
break;
case ',':
if (this.CharBuffer.isComment) {
this.CharBuffer.Append(char);
} else {
this.CharBuffer.Fill(FileName, row, column);
this.CharBuffer.Append(char);
this.CharBuffer.Fill(FileName, row, column);
}
break;
case ';':
if (this.CharBuffer.isComment) {
this.CharBuffer.Append(char);
} else {
this.CharBuffer.Fill(FileName, row, column);
this.CharBuffer.Append(char);
this.CharBuffer.Fill(FileName, row, column);
}
break;
case " ":
case "\t":
if (this.CharBuffer.isComment || ((this.CharBuffer.isOID || this.CharBuffer.nested > 0) && (!this.CharBuffer.isList || this.CharBuffer.inGroup > 0))) {
this.CharBuffer.Append(char);
} else {
this.CharBuffer.Fill(FileName, row, column);
}
break;
case "-":
this.CharBuffer.Append(char);
if (this.CharBuffer.lastChar == '-') {
this.CharBuffer.isComment = true;
this.CharBuffer.builder = this.CharBuffer.builder.split('--')[0];
this.CharBuffer.Fill(FileName, row, column);
this.CharBuffer.builder = '--';
}
break;
case '"':
if (this.CharBuffer.isComment && !this.CharBuffer.isString && !this.CharBuffer.inComment) {
//011 = COMMENT
//IF 011 SET 101
this.CharBuffer.isComment = true;
this.CharBuffer.isString = false;
this.CharBuffer.inComment = true;
} else if (!this.CharBuffer.isComment && !this.CharBuffer.isString && !this.CharBuffer.inComment) {
//000 = STRING
//IF 000 SET 110
this.CharBuffer.isComment = true;
this.CharBuffer.isString = true;
this.CharBuffer.inComment = false;
this.CharBuffer.Fill(FileName, row, column); //new string
} else if (this.CharBuffer.isComment && this.CharBuffer.isString && !this.CharBuffer.inComment) {
//110 = END STRING
//IF 110 SET 000
this.CharBuffer.isComment = false;
this.CharBuffer.isString = false;
this.CharBuffer.inComment = false;
} else if (this.CharBuffer.isComment && !this.CharBuffer.isString && this.CharBuffer.inComment) {
//101 = END COMMENT
//IF 101 SET 000
this.CharBuffer.isComment = true;
this.CharBuffer.isString = false;
this.CharBuffer.inComment = false;
}
if (this.CharBuffer.isComment) {
this.CharBuffer.Append(char);
} else {
this.CharBuffer.Append(char);
this.CharBuffer.Fill(FileName, row, column);
}
break;
default:
this.CharBuffer.Append(char);
break;
}
this.CharBuffer.lastChar = char;
},
Serialize: function () {
var Table = this.CharBuffer.Table;
var ModuleName = '';
for (var FileName in Table) {
ModuleName = this.CharBuffer.ModuleName[FileName];
this.SymbolBuffer[ModuleName] = [];
for (var r = 0; r < Table[FileName].length; r++) {
for (var c = 0; c < Table[FileName][r].length; c++) {
var symbol = Table[FileName][r][c];
switch (symbol) {
default:
if (symbol.indexOf('--') != 0) {//REMOVE COMMENTS
//console.log(ModuleName, symbol);
this.SymbolBuffer[ModuleName].push(symbol);
}
}
}
}
}
this.Compile();
},
Compile: function () {
for (var ModuleName in this.SymbolBuffer) {
if (this.SymbolBuffer.hasOwnProperty(ModuleName)) {
if (!this.Modules[ModuleName]) {
this.Modules[ModuleName] = {};
}
var Module = this.Modules[ModuleName];
var Symbols = this.SymbolBuffer[ModuleName];
var Object = Module;
var MACROName = '';
for (var i = 0; i < Symbols.length; i++) {
switch (Symbols[i]) {
case '::=': //new OBJECT to define
//if OBJECT IDENTIFIER tag IS NEXT, FIND MARCO TO CALL...
if (Symbols[i + 1].indexOf('{') == 0) {
var r = i - 1;
var found = false;
//Go back and find the MACRO to call
while (!found && r > 0) {
r--;
for (var m = 0; m < this.MACROS.length; m++) {
if (Symbols[r] == this.MACROS[m]) {
found = true;
break;
}
}
}
if (Symbols[i - 1] == 'OBJECT IDENTIFIER') {
Object[Symbols[i - 2]] = {};
Object[Symbols[i - 2]]['ObjectName'] = Symbols[i - 2];
Object[Symbols[i - 2]]['ModuleName'] = ModuleName;
Object[Symbols[i - 2]]['OBJECT IDENTIFIER'] = Symbols[i + 1].replace("{", "").replace("}", "").trim();
if (Object[Symbols[i - 2]]['OBJECT IDENTIFIER'] == '0 0') {
Object[Symbols[i - 2]]['OID'] = '0.0';
Object[Symbols[i - 2]]['NameSpace'] = 'null';
} else {
this.OID(Object[Symbols[i - 2]]['OBJECT IDENTIFIER'], '', Symbols[i - 2], '', function (ID, OD) {
Object[Symbols[i - 2]]['OID'] = ID;
Object[Symbols[i - 2]]['NameSpace'] = OD;
//Object[Symbols[i - 2]]['ModuleName'] = ModuleName;
// Object[Symbols[i - 2]]['ObjectName'] = Symbols[i - 2];
});
}
} else {
var ObjectName = Symbols[r - 1];
Object[ObjectName] = {};
Object[ObjectName]['ObjectName'] = ObjectName;
Object[ObjectName]['ModuleName'] = ModuleName;
Object[ObjectName]['MACRO'] = Symbols[r];
//BUILD OBJECT FROM MACRO TYPE NOTATION
var MARCO = this[Symbols[r]];
if (!MARCO) {
//HACK IF MARCO IS NOT FOUND
//MARCO = {};
//return;
}
var c1 = r;
var keychain = [];
keychain.push('DESCRIPTION');
var key;
for (var notation in MARCO['TYPE NOTATION']) {
key = notation;
//if TYPE NOTATION does not have a value
if (MARCO['TYPE NOTATION'][notation] == null) {
//then look up the value from the MACRO Root
key = MARCO[notation]['MACRO'].replace(/"/g, '');
}
keychain.push(key);
}
while (c1 < (i - 1)) {
c1++;
key = Symbols[c1]; //Parse TYPE NOTATION. ex: SYNTAX, ACCESS, STATUS, DESCRIPTION.....
//key == 'DESCRIPTION' ? console.log(keychain.indexOf(key), key, Symbols[c1 + 1]) : false;
var regExp = /\(([^)]+)\)/; //in parentheses ex: "ethernet-csmacd (6)"
if (keychain.indexOf(key) > -1 || key == 'REVISION') {
var val = Symbols[c1 + 1].replace(/"/g, "");
//if value array.
if (val.indexOf("{") == 0) {
c1++;
while (Symbols[c1].indexOf("}") == -1) {
c1++;
val += Symbols[c1];
}
if ( key == 'DEFVAL' ) {
// DEFVAL { 1500 } is not an array
val = val.replace(/^{/, '').replace(/}$/, '').trim();
} else {
// build value array
val = val.replace("{", "").replace("}", "").split(",");
}
}
switch (key) {
case 'SYNTAX':
switch (val) {
case 'BITS':
case 'INTEGER':
case 'Integer32':
// integer value array e.g. INTEGER {...rfc877-x25 (5), ethernet-csmacd (6)...}
if (Symbols[c1 + 2].indexOf("{") == 0) {
var valObj = val;
val = {};
val[valObj] = {};
c1 = c1 + 1;
var integer;
var syntax;
while (Symbols[c1].indexOf("}") == -1) {
c1++;
var ok = false;
if (Symbols[c1].indexOf("(") == 0 && Symbols[c1].length > 1) {
integer = regExp.exec(Symbols[c1]);
syntax = Symbols[c1 - 1];
ok = true;
} else if (Symbols[c1].indexOf("(") > 0) {
integer = regExp.exec(Symbols[c1]);
syntax = Symbols[c1].split("(")[0];
ok = true;
}
if (syntax && syntax.indexOf("{") == 0) {
syntax = syntax.split("{")[1].trim();
}
if (ok) {
val[valObj][integer[1]] = syntax;
}
}
// integer range e.g. INTEGER (1..2147483647)
} else if (Symbols[c1 + 2].indexOf("(") == 0) {
let valObj = val;
val = {};
val[valObj] = {
ranges: this.GetRanges(Symbols[c1 + 2])
};
}
break;
case 'OCTET STRING':
case 'DisplayString':
// string size e.g. OCTET STRING (SIZE (0..127))
if (Symbols[c1 + 2].replace(/ */g, '').startsWith('(SIZE')) {
let valObj = val;
val = {};
val[valObj] = {
sizes: this.GetRanges(Symbols[c1 + 2])
};
}
break;
case 'SEQUENCE OF':
val += ' ' + Symbols[c1 + 2];
c1 = c1 + 2;
break;
default:
break;
}
//SYNTAX value
Object[ObjectName][key] = val;
break;
case 'DESCRIPTION':
if ( ! Object[ObjectName][key] ) {
Object[ObjectName][key] = val;
}
if ( ! Object[ObjectName]['REVISIONS-DESCRIPTIONS'] ) {
Object[ObjectName]['REVISIONS-DESCRIPTIONS'] = [];
}
Object[ObjectName]['REVISIONS-DESCRIPTIONS'].push ({
"type": "DESCRIPTION",
"value": val
});
break;
case 'REVISION':
if ( ! Object[ObjectName]['REVISIONS-DESCRIPTIONS'] ) {
Object[ObjectName]['REVISIONS-DESCRIPTIONS'] = [];
}
Object[ObjectName]['REVISIONS-DESCRIPTIONS'].push ({
"type": "REVISION",
"value": val
});
break;
default:
Object[ObjectName][key] = val;
break;
}
}
}
Object[Symbols[r - 1]]['ObjectName'] = Symbols[r - 1];
Object[Symbols[r - 1]]['ModuleName'] = ModuleName;
Object[Symbols[r - 1]]['OBJECT IDENTIFIER'] = Symbols[i + 1].replace("{", "").replace("}", "").trim();
if (Object[Symbols[r - 1]]['OBJECT IDENTIFIER'] == '0 0') {
Object[Symbols[r - 1]]['OID'] = '0.0';
Object[Symbols[r - 1]]['NameSpace'] = 'null';
} else {
this.OID(Object[Symbols[r - 1]]['OBJECT IDENTIFIER'], '', Symbols[r - 1], '', function (ID, OD) {
Object[Symbols[r - 1]]['OID'] = ID;
Object[Symbols[r - 1]]['NameSpace'] = OD;
//Object[Symbols[r - 1]]['ModuleName'] = ModuleName;
//Object[Symbols[r - 1]]['ObjectName'] = Symbols[r - 1];
});
}
if ( Object[Symbols[r - 1]]['REVISIONS-DESCRIPTIONS'] &&
Object[Symbols[r - 1]]['REVISIONS-DESCRIPTIONS'].length == 1 &&
Object[Symbols[r - 1]]['REVISIONS-DESCRIPTIONS'][0]['type'] == 'DESCRIPTION' ) {
delete Object[Symbols[r - 1]]['REVISIONS-DESCRIPTIONS'];
}
}
} else {
//if OBJECT IDENTIFIER tag is NOT NEXT, check prior symbol for processing instructions / MARCO creation.
switch (Symbols[i - 1]) {
case 'DEFINITIONS':
break;
case 'OBJECT IDENTIFIER':
break;
case 'MACRO':
Object = Object[Symbols[i - 2]] = {};
MACROName = Symbols[i - 2];
break;
case 'VALUE NOTATION':
case 'TYPE NOTATION':
Object[Symbols[i - 1]] = {};
var j = i + 1;
while (Symbols[j + 1] != '::=' && Symbols[j + 1] != 'END') {
if (Symbols[j].indexOf('"') == 0) {
var value = Symbols[j + 1];
var t = j + 1;
if (Symbols[j + 2].indexOf('(') == 0) {
value = Symbols[j + 2];
t = j + 2;
}
Object[Symbols[i - 1]][Symbols[j].replace(/"/g, "")] = value;
j = t;
} else {
Object[Symbols[i - 1]][Symbols[j]] = null;
if (Symbols[j + 1].indexOf('(') == 0) {
Object[Symbols[i - 1]][Symbols[j]] = Symbols[j + 1];
j++;
}
}
j++;
}
// Workaround for lack of INDEX, AUGMENTS and ACCESS in OBJECT-TYPE MACRO "TYPE NOTATION"
if ( ModuleName == "SNMPv2-SMI" ) {
Object["TYPE NOTATION"].INDEX = "Index";
Object["TYPE NOTATION"].AUGMENTS = "Augments";
Object["TYPE NOTATION"].ACCESS = "Access";
} else if ( ModuleName == "RFC-1212" ) {
Object["TYPE NOTATION"].INDEX = "Index";
Object["TYPE NOTATION"].ACCESS = "Access";
}
// End INDEX/AUGMENTS workaround
break;
default:
//new object
Object[Symbols[i - 1]] = {};
Object[Symbols[i - 1]]['ObjectName'] = Symbols[i - 1];
Object[Symbols[i - 1]]['ModuleName'] = ModuleName;
Object[Symbols[i - 1]]['MACRO'] = Symbols[i + 1];
this.BuildObject(Object, Symbols[i - 1], Symbols[i + 1], i, Symbols);
break;
}
}
break;
case 'END':
if (MACROName != '') {
//ADD macros to root for easier processing
//Still need Import feature
this[MACROName] = Object;
this.MACROS.push(MACROName);
}
//reset Object to Module root;
Object = Module;
MACROName = '';
break;
case 'IMPORTS':
//console.log(ModuleName, 'IMPORTS');
//i++;
Module['IMPORTS'] = {};
var tmp = i + 1;
var IMPORTS = [];
while (Symbols[tmp] != ';') {
if (Symbols[tmp] == 'FROM') {
var ImportModule = Symbols[tmp + 1];
if (!this.Modules[ImportModule]) {
console.log(ModuleName + ': Can not find ' + ImportModule + '!!!!!!!!!!!!!!!!!!!!!');
console.log(ModuleName + ': Can not import ', IMPORTS);
}
Module['IMPORTS'][ImportModule] = IMPORTS;
tmp++;
IMPORTS = [];
} else if (Symbols[tmp] != ',') {
IMPORTS.push(Symbols[tmp]);
}
tmp++;
}
//console.log(ModuleName, 'IMPORTS', Module['IMPORTS']);
break;
case 'EXPORTS':
//console.log(ModuleName, 'EXPORTS');
break;
default:
break;
}
}
}
}
},
GetRanges: function (mibRanges) {
let rangesString = mibRanges.replace(/ */g, '').replace(/\(SIZE/, '').replace(/\)/, '').replace(/\(/, '').replace(/\)/, '');
let rangeStrings = rangesString.split('|');
let ranges = [];
for ( let rangeString of rangeStrings ) {
if ( rangeString.includes('..') ) {
let range = rangeString.split('..');
ranges.push({
min: parseInt(range[0], 10),
max: parseInt(range[1], 10)
});
} else {
ranges.push({
min: parseInt(rangeString, 10),
max: parseInt(rangeString, 10)
});
}
}
return ranges;
},
BuildObject: function (Object, ObjectName, macro, i, Symbols) {
var r = i;
var m = Symbols.indexOf('SYNTAX', r) - r;
var SYNTAX = Symbols[Symbols.indexOf('SYNTAX', r) + 1];
var val = Symbols[Symbols.indexOf('SYNTAX', r) + 2];
var c1 = Symbols.indexOf('SYNTAX', r) + 1;
if (this.MACROS.indexOf(macro) > -1 && m < 10) {
switch (SYNTAX) {
case "INTEGER":
if (val.indexOf("{") == 0) {
c1++;
while (Symbols[c1].indexOf("}") == -1) {
c1++;
val += Symbols[c1].trim();
}
val = val.replace("{", "").replace("}", "").split(",");
Object[ObjectName]['SYNTAX'] = {};
Object[ObjectName]['SYNTAX'][SYNTAX] = {};
for (var TC = 0; TC < val.length; TC++) {
Object[ObjectName]['SYNTAX'][SYNTAX][val[TC].split("(")[1].replace(")", "")] = val[TC].split("(")[0];
}
}
break;
default:
Object[ObjectName]['SYNTAX'] = SYNTAX;
break;
}
}
},
GetSummary: function (callback) {
var summary = '';
for (var ModuleName in this.Modules) {
if (this.Modules.hasOwnProperty(ModuleName)) {
for (var ObjectName in this.Modules[ModuleName]) {
if (this.Modules[ModuleName].hasOwnProperty(ObjectName)) {
if (this.Modules[ModuleName][ObjectName]['OID']) {
//OID
summary += this.Modules[ModuleName][ObjectName]['OID'] + " : " + ObjectName + '\r\n';
//callback(this.Modules[ModuleName][ObjectName]);
//break;
}
}
}
}
}
callback(summary);
},
OID: function (OBJECT_IDENTIFIER, ID, ObjectName, OD, callback) {
let members = OBJECT_IDENTIFIER.split(" ");
let parent = members.shift();
let oid = members.pop();
if (parent == 'iso') {
let midID = ['1'];
let midOD = ['iso'];
for (let entry of members) {
let match = entry.match(/(.*)\((.+)\)$/);
midID.push(match[2]);
midOD.push(match[1]);
}
midID.push(oid);
if ( ID != '' ) {
midID.push(ID);
}
if ( OD != '' ) {
midOD.push(OD);
}
midOD.push(ObjectName);
callback(midID.join('.'), midOD.join('.'));
return;
}
ID = ID == '' ? oid : [oid, ID].join('.');
OD = OD == '' ? parent : [parent, OD].join('.');
for (var ModuleName in this.Modules) {
if (this.Modules.hasOwnProperty(ModuleName)) {
if (this.Modules[ModuleName][parent]) {
this.OID(this.Modules[ModuleName][parent]["OBJECT IDENTIFIER"], ID, ObjectName, OD, callback);
break;
}
}
}
}
});
};
module.exports = exports = MIB;
exports.MIB = MIB;
exports.native = undefined;