@ethernity-cloud/runner
Version:
506 lines (439 loc) • 12.2 kB
JavaScript
/* eslint-disable */
const { Buffer } = require('buffer/');
/**
* Copyright 2015 Huan Du. All rights reserved.
* Licensed under the MIT license that can be found in the LICENSE file.
*/
// Buffer api is changed since v6.0.0. this wrapper is designed to leverage new
// api features if possible without breaking old node.
//
// it's not a completed polyfill implementation. i just do necessary shims for this
// package only.
const _BufferFrom =
Buffer.from ||
function () {
switch (arguments.length) {
case 1:
return new Buffer(arguments[0]);
case 2:
return new Buffer(arguments[0], arguments[1]);
case 3:
return new Buffer(arguments[0], arguments[1], arguments[2]);
default:
throw new Exception('unexpected call.');
}
};
const _BufferAlloc =
Buffer.alloc ||
function (size, fill, encoding) {
const buf = new Buffer(size);
if (fill !== undefined) {
if (typeof encoding === 'string') {
buf.fill(fill, encoding);
} else {
buf.fill(fill);
}
}
return buf;
};
const _BufferAllocUnsafe =
Buffer.allocUnsafe ||
function (size) {
return new Buffer(size);
};
const _NewUint8Array = (function () {
if (typeof Uint8Array === 'undefined') {
return function (size) {
return new Array(size);
};
}
return function (size) {
return new Uint8Array(size);
};
})();
const ASCII85_BASE = 85;
const ASCII85_CODE_START = 33;
const ASCII85_CODE_END = ASCII85_CODE_START + ASCII85_BASE;
const ASCII85_NULL = String.fromCharCode(0);
const ASCII85_NULL_STRING = ASCII85_NULL + ASCII85_NULL + ASCII85_NULL + ASCII85_NULL;
const ASCII85_ZERO = 'z';
const ASCII85_ZERO_VALUE = ASCII85_ZERO.charCodeAt(0);
const ASCII85_PADDING_VALUE = 'u'.charCodeAt(0);
const ASCII85_ENCODING_GROUP_LENGTH = 4;
const ASCII85_DECODING_GROUP_LENGTH = 5;
const ASCII85_BLOCK_START = '<~';
const ASCII85_BLOCK_START_LENGTH = ASCII85_BLOCK_START.length;
const ASCII85_BLOCK_START_VALUE = _BufferFrom(ASCII85_BLOCK_START).readUInt16BE(0);
const ASCII85_BLOCK_END = '~>';
const ASCII85_BLOCK_END_LENGTH = ASCII85_BLOCK_END.length;
const ASCII85_BLOCK_END_VALUE = _BufferFrom(ASCII85_BLOCK_END).readUInt16BE(0);
const ASCII85_GROUP_SPACE = 'y';
const ASCII85_GROUP_SPACE_VALUE = ASCII85_GROUP_SPACE.charCodeAt(0);
const ASCII85_GROUP_SPACE_CODE = 0x20202020;
const ASCII85_GROUP_SPACE_STRING = ' ';
const ASCII85_DEFAULT_ENCODING_TABLE = (function () {
const arr = new Array(ASCII85_BASE);
let i;
for (i = 0; i < ASCII85_BASE; i++) {
arr[i] = String.fromCharCode(ASCII85_CODE_START + i);
}
return arr;
})();
const ASCII85_DEFAULT_DECODING_TABLE = (function () {
const arr = new Array(1 << 8);
let i;
for (i = 0; i < ASCII85_BASE; i++) {
arr[ASCII85_CODE_START + i] = i;
}
return arr;
})();
/**
* Create a new Ascii85 codec.
* @param {Array|Object} [options] is a list of chars for encoding or an option object.
*
* Supported options are listed in Ascii85#encode document.
* @note Only encoding table is supported. Decoding table will be generated automatically
* based on encoding table.
*/
function Ascii85(options) {
let decodingTable;
options = options || {};
this._options = options;
// generate encoding and decoding table.
if (Array.isArray(options.table)) {
decodingTable = [];
options.table.forEach((v, i) => {
decodingTable[v.charCodeAt(0)] = i;
});
options.encodingTable = options.table;
options.decodingTable = decodingTable;
}
}
const defaultCodec = (module.exports = new Ascii85());
/**
* Encode a binary data to ascii85 string.
* @param {String|Buffer} data is a string or Buffer.
* @param {Array|Object} [options] is a list of chars for encoding or an option object.
* If no options is provided, encode uses standard ascii85
* char table to encode data.
*
* Supported options are following.
* - table: Table for encoding. Default is ASCII85_DEFAULT_ENCODING_TABLE.
* - delimiter: Add '<~' and '~>' to output. Default is false.
* - groupSpace: Support group of all spaces in btoa 4.2. Default is false.
*/
Ascii85.prototype.encode = function (data, options) {
const bytes = _NewUint8Array(5);
let buf = data;
const defOptions = this._options;
let output;
let offset;
let table;
let delimiter;
let groupSpace;
let digits;
let cur;
let i;
let j;
let r;
let b;
let len;
let padding;
if (typeof buf === 'string') {
buf = _BufferFrom(buf, 'binary');
} else if (!(buf instanceof Buffer)) {
buf = _BufferFrom(buf);
}
// prepare options.
options = options || {};
if (Array.isArray(options)) {
table = options;
delimiter = defOptions.delimiter || false;
groupSpace = defOptions.groupSpace || false;
} else {
table = options.table || defOptions.encodingTable || ASCII85_DEFAULT_ENCODING_TABLE;
if (options.delimiter === undefined) {
delimiter = defOptions.delimiter || false;
} else {
delimiter = !!options.delimiter;
}
if (options.groupSpace === undefined) {
groupSpace = defOptions.groupSpace || false;
} else {
groupSpace = !!options.groupSpace;
}
}
// estimate output length and alloc buffer for it.
offset = 0;
len =
Math.ceil((buf.length * ASCII85_DECODING_GROUP_LENGTH) / ASCII85_ENCODING_GROUP_LENGTH) +
ASCII85_ENCODING_GROUP_LENGTH +
(delimiter ? ASCII85_BLOCK_START_LENGTH + ASCII85_BLOCK_END_LENGTH : 0);
output = _BufferAllocUnsafe(len);
if (delimiter) {
offset += output.write(ASCII85_BLOCK_START, offset);
}
// iterate over all data bytes.
for (i = digits = cur = 0, len = buf.length; i < len; i++) {
b = buf.readUInt8(i);
cur *= 1 << 8;
cur += b;
digits++;
if (digits % ASCII85_ENCODING_GROUP_LENGTH) {
continue;
}
if (groupSpace && cur === ASCII85_GROUP_SPACE_CODE) {
offset += output.write(ASCII85_GROUP_SPACE, offset);
} else if (cur) {
for (j = ASCII85_ENCODING_GROUP_LENGTH; j >= 0; j--) {
r = cur % ASCII85_BASE;
bytes[j] = r;
cur = (cur - r) / ASCII85_BASE;
}
for (j = 0; j < ASCII85_DECODING_GROUP_LENGTH; j++) {
offset += output.write(table[bytes[j]], offset);
}
} else {
offset += output.write(ASCII85_ZERO, offset);
}
cur = 0;
digits = 0;
}
// add padding for remaining bytes.
if (digits) {
if (cur) {
padding = ASCII85_ENCODING_GROUP_LENGTH - digits;
for (i = ASCII85_ENCODING_GROUP_LENGTH - digits; i > 0; i--) {
cur *= 1 << 8;
}
for (j = ASCII85_ENCODING_GROUP_LENGTH; j >= 0; j--) {
r = cur % ASCII85_BASE;
bytes[j] = r;
cur = (cur - r) / ASCII85_BASE;
}
for (j = 0; j < ASCII85_DECODING_GROUP_LENGTH; j++) {
offset += output.write(table[bytes[j]], offset);
}
offset -= padding;
} else {
// If remaining bytes are zero, need to insert '!' instead of 'z'.
// This is a special case.
for (i = 0; i < digits + 1; i++) {
offset += output.write(table[0], offset);
}
}
}
if (delimiter) {
offset += output.write(ASCII85_BLOCK_END, offset);
}
return output.slice(0, offset);
};
/**
* Decode a string to binary data.
* @param {String|Buffer} data is a string or Buffer.
* @param {Array|Object} [table] is a sparse array to map char code and decoded value for decoding.
* Default is standard table.
*/
Ascii85.prototype.decode = function (str, table) {
const defOptions = this._options;
let buf = str;
let enableZero = true;
let enableGroupSpace = true;
let output;
let offset;
let digits;
let cur;
let i;
let c;
let t;
let len;
let padding;
table = table || defOptions.decodingTable || ASCII85_DEFAULT_DECODING_TABLE;
// convert a key/value format char map to code array.
if (!Array.isArray(table)) {
table = table.table || table;
if (!Array.isArray(table)) {
t = [];
Object.keys(table).forEach((v) => {
t[v.charCodeAt(0)] = table[v];
});
table = t;
}
}
enableZero = !table[ASCII85_ZERO_VALUE];
enableGroupSpace = !table[ASCII85_GROUP_SPACE_VALUE];
if (!(buf instanceof Buffer)) {
buf = _BufferFrom(buf);
}
// estimate output length and alloc buffer for it.
t = 0;
if (enableZero || enableGroupSpace) {
for (i = 0, len = buf.length; i < len; i++) {
c = buf.readUInt8(i);
if (enableZero && c === ASCII85_ZERO_VALUE) {
t++;
}
if (enableGroupSpace && c === ASCII85_GROUP_SPACE_VALUE) {
t++;
}
}
}
offset = 0;
len =
Math.ceil((buf.length * ASCII85_ENCODING_GROUP_LENGTH) / ASCII85_DECODING_GROUP_LENGTH) +
t * ASCII85_ENCODING_GROUP_LENGTH +
ASCII85_DECODING_GROUP_LENGTH;
output = _BufferAllocUnsafe(len);
// if str starts with delimiter ('<~'), it must end with '~>'.
if (
buf.length >= ASCII85_BLOCK_START_LENGTH + ASCII85_BLOCK_END_LENGTH &&
buf.readUInt16BE(0) === ASCII85_BLOCK_START_VALUE
) {
for (i = buf.length - ASCII85_BLOCK_END_LENGTH; i > ASCII85_BLOCK_START_LENGTH; i--) {
if (buf.readUInt16BE(i) === ASCII85_BLOCK_END_VALUE) {
break;
}
}
if (i <= ASCII85_BLOCK_START_LENGTH) {
throw new Error('Invalid ascii85 string delimiter pair.');
}
buf = buf.slice(ASCII85_BLOCK_START_LENGTH, i);
}
for (i = digits = cur = 0, len = buf.length; i < len; i++) {
c = buf.readUInt8(i);
if (enableZero && c === ASCII85_ZERO_VALUE) {
offset += output.write(ASCII85_NULL_STRING, offset);
continue;
}
if (enableGroupSpace && c === ASCII85_GROUP_SPACE_VALUE) {
offset += output.write(ASCII85_GROUP_SPACE_STRING, offset);
continue;
}
if (table[c] === undefined) {
continue;
}
cur *= ASCII85_BASE;
cur += table[c];
digits++;
if (digits % ASCII85_DECODING_GROUP_LENGTH) {
continue;
}
offset = output.writeUInt32BE(cur, offset);
cur = 0;
digits = 0;
}
if (digits) {
padding = ASCII85_DECODING_GROUP_LENGTH - digits;
for (i = 0; i < padding; i++) {
cur *= ASCII85_BASE;
cur += ASCII85_BASE - 1;
}
for (i = 3, len = padding - 1; i > len; i--) {
offset = output.writeUInt8((cur >>> (i * 8)) & 0xff, offset);
}
}
return output.slice(0, offset);
};
/**
* Ascii85 for ZeroMQ which uses a different codec table.
*/
defaultCodec.ZeroMQ = new Ascii85({
table: [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'.',
'-',
':',
'+',
'=',
'^',
'!',
'/',
'*',
'?',
'&',
'<',
'>',
'(',
')',
'[',
']',
'{',
'}',
'@',
'%',
'$',
'#'
]
});
/**
* Ascii85 for PostScript which always uses delimiter for encoding.
*/
defaultCodec.PostScript = new Ascii85({
delimiter: true
});
/**
* Ascii85 codec constructor.
*/
defaultCodec.Ascii85 = Ascii85;
module.exports = defaultCodec;