node.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. 'use strict';
  2. const Reporter = require('../base/reporter').Reporter;
  3. const EncoderBuffer = require('../base/buffer').EncoderBuffer;
  4. const DecoderBuffer = require('../base/buffer').DecoderBuffer;
  5. const assert = require('minimalistic-assert');
  6. // Supported tags
  7. const tags = [
  8. 'seq', 'seqof', 'set', 'setof', 'objid', 'bool',
  9. 'gentime', 'utctime', 'null_', 'enum', 'int', 'objDesc',
  10. 'bitstr', 'bmpstr', 'charstr', 'genstr', 'graphstr', 'ia5str', 'iso646str',
  11. 'numstr', 'octstr', 'printstr', 't61str', 'unistr', 'utf8str', 'videostr'
  12. ];
  13. // Public methods list
  14. const methods = [
  15. 'key', 'obj', 'use', 'optional', 'explicit', 'implicit', 'def', 'choice',
  16. 'any', 'contains'
  17. ].concat(tags);
  18. // Overrided methods list
  19. const overrided = [
  20. '_peekTag', '_decodeTag', '_use',
  21. '_decodeStr', '_decodeObjid', '_decodeTime',
  22. '_decodeNull', '_decodeInt', '_decodeBool', '_decodeList',
  23. '_encodeComposite', '_encodeStr', '_encodeObjid', '_encodeTime',
  24. '_encodeNull', '_encodeInt', '_encodeBool'
  25. ];
  26. function Node(enc, parent, name) {
  27. const state = {};
  28. this._baseState = state;
  29. state.name = name;
  30. state.enc = enc;
  31. state.parent = parent || null;
  32. state.children = null;
  33. // State
  34. state.tag = null;
  35. state.args = null;
  36. state.reverseArgs = null;
  37. state.choice = null;
  38. state.optional = false;
  39. state.any = false;
  40. state.obj = false;
  41. state.use = null;
  42. state.useDecoder = null;
  43. state.key = null;
  44. state['default'] = null;
  45. state.explicit = null;
  46. state.implicit = null;
  47. state.contains = null;
  48. // Should create new instance on each method
  49. if (!state.parent) {
  50. state.children = [];
  51. this._wrap();
  52. }
  53. }
  54. module.exports = Node;
  55. const stateProps = [
  56. 'enc', 'parent', 'children', 'tag', 'args', 'reverseArgs', 'choice',
  57. 'optional', 'any', 'obj', 'use', 'alteredUse', 'key', 'default', 'explicit',
  58. 'implicit', 'contains'
  59. ];
  60. Node.prototype.clone = function clone() {
  61. const state = this._baseState;
  62. const cstate = {};
  63. stateProps.forEach(function(prop) {
  64. cstate[prop] = state[prop];
  65. });
  66. const res = new this.constructor(cstate.parent);
  67. res._baseState = cstate;
  68. return res;
  69. };
  70. Node.prototype._wrap = function wrap() {
  71. const state = this._baseState;
  72. methods.forEach(function(method) {
  73. this[method] = function _wrappedMethod() {
  74. const clone = new this.constructor(this);
  75. state.children.push(clone);
  76. return clone[method].apply(clone, arguments);
  77. };
  78. }, this);
  79. };
  80. Node.prototype._init = function init(body) {
  81. const state = this._baseState;
  82. assert(state.parent === null);
  83. body.call(this);
  84. // Filter children
  85. state.children = state.children.filter(function(child) {
  86. return child._baseState.parent === this;
  87. }, this);
  88. assert.equal(state.children.length, 1, 'Root node can have only one child');
  89. };
  90. Node.prototype._useArgs = function useArgs(args) {
  91. const state = this._baseState;
  92. // Filter children and args
  93. const children = args.filter(function(arg) {
  94. return arg instanceof this.constructor;
  95. }, this);
  96. args = args.filter(function(arg) {
  97. return !(arg instanceof this.constructor);
  98. }, this);
  99. if (children.length !== 0) {
  100. assert(state.children === null);
  101. state.children = children;
  102. // Replace parent to maintain backward link
  103. children.forEach(function(child) {
  104. child._baseState.parent = this;
  105. }, this);
  106. }
  107. if (args.length !== 0) {
  108. assert(state.args === null);
  109. state.args = args;
  110. state.reverseArgs = args.map(function(arg) {
  111. if (typeof arg !== 'object' || arg.constructor !== Object)
  112. return arg;
  113. const res = {};
  114. Object.keys(arg).forEach(function(key) {
  115. if (key == (key | 0))
  116. key |= 0;
  117. const value = arg[key];
  118. res[value] = key;
  119. });
  120. return res;
  121. });
  122. }
  123. };
  124. //
  125. // Overrided methods
  126. //
  127. overrided.forEach(function(method) {
  128. Node.prototype[method] = function _overrided() {
  129. const state = this._baseState;
  130. throw new Error(method + ' not implemented for encoding: ' + state.enc);
  131. };
  132. });
  133. //
  134. // Public methods
  135. //
  136. tags.forEach(function(tag) {
  137. Node.prototype[tag] = function _tagMethod() {
  138. const state = this._baseState;
  139. const args = Array.prototype.slice.call(arguments);
  140. assert(state.tag === null);
  141. state.tag = tag;
  142. this._useArgs(args);
  143. return this;
  144. };
  145. });
  146. Node.prototype.use = function use(item) {
  147. assert(item);
  148. const state = this._baseState;
  149. assert(state.use === null);
  150. state.use = item;
  151. return this;
  152. };
  153. Node.prototype.optional = function optional() {
  154. const state = this._baseState;
  155. state.optional = true;
  156. return this;
  157. };
  158. Node.prototype.def = function def(val) {
  159. const state = this._baseState;
  160. assert(state['default'] === null);
  161. state['default'] = val;
  162. state.optional = true;
  163. return this;
  164. };
  165. Node.prototype.explicit = function explicit(num) {
  166. const state = this._baseState;
  167. assert(state.explicit === null && state.implicit === null);
  168. state.explicit = num;
  169. return this;
  170. };
  171. Node.prototype.implicit = function implicit(num) {
  172. const state = this._baseState;
  173. assert(state.explicit === null && state.implicit === null);
  174. state.implicit = num;
  175. return this;
  176. };
  177. Node.prototype.obj = function obj() {
  178. const state = this._baseState;
  179. const args = Array.prototype.slice.call(arguments);
  180. state.obj = true;
  181. if (args.length !== 0)
  182. this._useArgs(args);
  183. return this;
  184. };
  185. Node.prototype.key = function key(newKey) {
  186. const state = this._baseState;
  187. assert(state.key === null);
  188. state.key = newKey;
  189. return this;
  190. };
  191. Node.prototype.any = function any() {
  192. const state = this._baseState;
  193. state.any = true;
  194. return this;
  195. };
  196. Node.prototype.choice = function choice(obj) {
  197. const state = this._baseState;
  198. assert(state.choice === null);
  199. state.choice = obj;
  200. this._useArgs(Object.keys(obj).map(function(key) {
  201. return obj[key];
  202. }));
  203. return this;
  204. };
  205. Node.prototype.contains = function contains(item) {
  206. const state = this._baseState;
  207. assert(state.use === null);
  208. state.contains = item;
  209. return this;
  210. };
  211. //
  212. // Decoding
  213. //
  214. Node.prototype._decode = function decode(input, options) {
  215. const state = this._baseState;
  216. // Decode root node
  217. if (state.parent === null)
  218. return input.wrapResult(state.children[0]._decode(input, options));
  219. let result = state['default'];
  220. let present = true;
  221. let prevKey = null;
  222. if (state.key !== null)
  223. prevKey = input.enterKey(state.key);
  224. // Check if tag is there
  225. if (state.optional) {
  226. let tag = null;
  227. if (state.explicit !== null)
  228. tag = state.explicit;
  229. else if (state.implicit !== null)
  230. tag = state.implicit;
  231. else if (state.tag !== null)
  232. tag = state.tag;
  233. if (tag === null && !state.any) {
  234. // Trial and Error
  235. const save = input.save();
  236. try {
  237. if (state.choice === null)
  238. this._decodeGeneric(state.tag, input, options);
  239. else
  240. this._decodeChoice(input, options);
  241. present = true;
  242. } catch (e) {
  243. present = false;
  244. }
  245. input.restore(save);
  246. } else {
  247. present = this._peekTag(input, tag, state.any);
  248. if (input.isError(present))
  249. return present;
  250. }
  251. }
  252. // Push object on stack
  253. let prevObj;
  254. if (state.obj && present)
  255. prevObj = input.enterObject();
  256. if (present) {
  257. // Unwrap explicit values
  258. if (state.explicit !== null) {
  259. const explicit = this._decodeTag(input, state.explicit);
  260. if (input.isError(explicit))
  261. return explicit;
  262. input = explicit;
  263. }
  264. const start = input.offset;
  265. // Unwrap implicit and normal values
  266. if (state.use === null && state.choice === null) {
  267. let save;
  268. if (state.any)
  269. save = input.save();
  270. const body = this._decodeTag(
  271. input,
  272. state.implicit !== null ? state.implicit : state.tag,
  273. state.any
  274. );
  275. if (input.isError(body))
  276. return body;
  277. if (state.any)
  278. result = input.raw(save);
  279. else
  280. input = body;
  281. }
  282. if (options && options.track && state.tag !== null)
  283. options.track(input.path(), start, input.length, 'tagged');
  284. if (options && options.track && state.tag !== null)
  285. options.track(input.path(), input.offset, input.length, 'content');
  286. // Select proper method for tag
  287. if (state.any) {
  288. // no-op
  289. } else if (state.choice === null) {
  290. result = this._decodeGeneric(state.tag, input, options);
  291. } else {
  292. result = this._decodeChoice(input, options);
  293. }
  294. if (input.isError(result))
  295. return result;
  296. // Decode children
  297. if (!state.any && state.choice === null && state.children !== null) {
  298. state.children.forEach(function decodeChildren(child) {
  299. // NOTE: We are ignoring errors here, to let parser continue with other
  300. // parts of encoded data
  301. child._decode(input, options);
  302. });
  303. }
  304. // Decode contained/encoded by schema, only in bit or octet strings
  305. if (state.contains && (state.tag === 'octstr' || state.tag === 'bitstr')) {
  306. const data = new DecoderBuffer(result);
  307. result = this._getUse(state.contains, input._reporterState.obj)
  308. ._decode(data, options);
  309. }
  310. }
  311. // Pop object
  312. if (state.obj && present)
  313. result = input.leaveObject(prevObj);
  314. // Set key
  315. if (state.key !== null && (result !== null || present === true))
  316. input.leaveKey(prevKey, state.key, result);
  317. else if (prevKey !== null)
  318. input.exitKey(prevKey);
  319. return result;
  320. };
  321. Node.prototype._decodeGeneric = function decodeGeneric(tag, input, options) {
  322. const state = this._baseState;
  323. if (tag === 'seq' || tag === 'set')
  324. return null;
  325. if (tag === 'seqof' || tag === 'setof')
  326. return this._decodeList(input, tag, state.args[0], options);
  327. else if (/str$/.test(tag))
  328. return this._decodeStr(input, tag, options);
  329. else if (tag === 'objid' && state.args)
  330. return this._decodeObjid(input, state.args[0], state.args[1], options);
  331. else if (tag === 'objid')
  332. return this._decodeObjid(input, null, null, options);
  333. else if (tag === 'gentime' || tag === 'utctime')
  334. return this._decodeTime(input, tag, options);
  335. else if (tag === 'null_')
  336. return this._decodeNull(input, options);
  337. else if (tag === 'bool')
  338. return this._decodeBool(input, options);
  339. else if (tag === 'objDesc')
  340. return this._decodeStr(input, tag, options);
  341. else if (tag === 'int' || tag === 'enum')
  342. return this._decodeInt(input, state.args && state.args[0], options);
  343. if (state.use !== null) {
  344. return this._getUse(state.use, input._reporterState.obj)
  345. ._decode(input, options);
  346. } else {
  347. return input.error('unknown tag: ' + tag);
  348. }
  349. };
  350. Node.prototype._getUse = function _getUse(entity, obj) {
  351. const state = this._baseState;
  352. // Create altered use decoder if implicit is set
  353. state.useDecoder = this._use(entity, obj);
  354. assert(state.useDecoder._baseState.parent === null);
  355. state.useDecoder = state.useDecoder._baseState.children[0];
  356. if (state.implicit !== state.useDecoder._baseState.implicit) {
  357. state.useDecoder = state.useDecoder.clone();
  358. state.useDecoder._baseState.implicit = state.implicit;
  359. }
  360. return state.useDecoder;
  361. };
  362. Node.prototype._decodeChoice = function decodeChoice(input, options) {
  363. const state = this._baseState;
  364. let result = null;
  365. let match = false;
  366. Object.keys(state.choice).some(function(key) {
  367. const save = input.save();
  368. const node = state.choice[key];
  369. try {
  370. const value = node._decode(input, options);
  371. if (input.isError(value))
  372. return false;
  373. result = { type: key, value: value };
  374. match = true;
  375. } catch (e) {
  376. input.restore(save);
  377. return false;
  378. }
  379. return true;
  380. }, this);
  381. if (!match)
  382. return input.error('Choice not matched');
  383. return result;
  384. };
  385. //
  386. // Encoding
  387. //
  388. Node.prototype._createEncoderBuffer = function createEncoderBuffer(data) {
  389. return new EncoderBuffer(data, this.reporter);
  390. };
  391. Node.prototype._encode = function encode(data, reporter, parent) {
  392. const state = this._baseState;
  393. if (state['default'] !== null && state['default'] === data)
  394. return;
  395. const result = this._encodeValue(data, reporter, parent);
  396. if (result === undefined)
  397. return;
  398. if (this._skipDefault(result, reporter, parent))
  399. return;
  400. return result;
  401. };
  402. Node.prototype._encodeValue = function encode(data, reporter, parent) {
  403. const state = this._baseState;
  404. // Decode root node
  405. if (state.parent === null)
  406. return state.children[0]._encode(data, reporter || new Reporter());
  407. let result = null;
  408. // Set reporter to share it with a child class
  409. this.reporter = reporter;
  410. // Check if data is there
  411. if (state.optional && data === undefined) {
  412. if (state['default'] !== null)
  413. data = state['default'];
  414. else
  415. return;
  416. }
  417. // Encode children first
  418. let content = null;
  419. let primitive = false;
  420. if (state.any) {
  421. // Anything that was given is translated to buffer
  422. result = this._createEncoderBuffer(data);
  423. } else if (state.choice) {
  424. result = this._encodeChoice(data, reporter);
  425. } else if (state.contains) {
  426. content = this._getUse(state.contains, parent)._encode(data, reporter);
  427. primitive = true;
  428. } else if (state.children) {
  429. content = state.children.map(function(child) {
  430. if (child._baseState.tag === 'null_')
  431. return child._encode(null, reporter, data);
  432. if (child._baseState.key === null)
  433. return reporter.error('Child should have a key');
  434. const prevKey = reporter.enterKey(child._baseState.key);
  435. if (typeof data !== 'object')
  436. return reporter.error('Child expected, but input is not object');
  437. const res = child._encode(data[child._baseState.key], reporter, data);
  438. reporter.leaveKey(prevKey);
  439. return res;
  440. }, this).filter(function(child) {
  441. return child;
  442. });
  443. content = this._createEncoderBuffer(content);
  444. } else {
  445. if (state.tag === 'seqof' || state.tag === 'setof') {
  446. // TODO(indutny): this should be thrown on DSL level
  447. if (!(state.args && state.args.length === 1))
  448. return reporter.error('Too many args for : ' + state.tag);
  449. if (!Array.isArray(data))
  450. return reporter.error('seqof/setof, but data is not Array');
  451. const child = this.clone();
  452. child._baseState.implicit = null;
  453. content = this._createEncoderBuffer(data.map(function(item) {
  454. const state = this._baseState;
  455. return this._getUse(state.args[0], data)._encode(item, reporter);
  456. }, child));
  457. } else if (state.use !== null) {
  458. result = this._getUse(state.use, parent)._encode(data, reporter);
  459. } else {
  460. content = this._encodePrimitive(state.tag, data);
  461. primitive = true;
  462. }
  463. }
  464. // Encode data itself
  465. if (!state.any && state.choice === null) {
  466. const tag = state.implicit !== null ? state.implicit : state.tag;
  467. const cls = state.implicit === null ? 'universal' : 'context';
  468. if (tag === null) {
  469. if (state.use === null)
  470. reporter.error('Tag could be omitted only for .use()');
  471. } else {
  472. if (state.use === null)
  473. result = this._encodeComposite(tag, primitive, cls, content);
  474. }
  475. }
  476. // Wrap in explicit
  477. if (state.explicit !== null)
  478. result = this._encodeComposite(state.explicit, false, 'context', result);
  479. return result;
  480. };
  481. Node.prototype._encodeChoice = function encodeChoice(data, reporter) {
  482. const state = this._baseState;
  483. const node = state.choice[data.type];
  484. if (!node) {
  485. assert(
  486. false,
  487. data.type + ' not found in ' +
  488. JSON.stringify(Object.keys(state.choice)));
  489. }
  490. return node._encode(data.value, reporter);
  491. };
  492. Node.prototype._encodePrimitive = function encodePrimitive(tag, data) {
  493. const state = this._baseState;
  494. if (/str$/.test(tag))
  495. return this._encodeStr(data, tag);
  496. else if (tag === 'objid' && state.args)
  497. return this._encodeObjid(data, state.reverseArgs[0], state.args[1]);
  498. else if (tag === 'objid')
  499. return this._encodeObjid(data, null, null);
  500. else if (tag === 'gentime' || tag === 'utctime')
  501. return this._encodeTime(data, tag);
  502. else if (tag === 'null_')
  503. return this._encodeNull();
  504. else if (tag === 'int' || tag === 'enum')
  505. return this._encodeInt(data, state.args && state.reverseArgs[0]);
  506. else if (tag === 'bool')
  507. return this._encodeBool(data);
  508. else if (tag === 'objDesc')
  509. return this._encodeStr(data, tag);
  510. else
  511. throw new Error('Unsupported tag: ' + tag);
  512. };
  513. Node.prototype._isNumstr = function isNumstr(str) {
  514. return /^[0-9 ]*$/.test(str);
  515. };
  516. Node.prototype._isPrintstr = function isPrintstr(str) {
  517. return /^[A-Za-z0-9 '()+,-./:=?]*$/.test(str);
  518. };