biner
Version:
Declarative binary data encoder / decoder.
148 lines • 4.83 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const decode_1 = require("../decode");
const encode_1 = require("../encode");
const encoding_length_1 = require("../encoding-length");
const util_1 = require("../util");
const meta_1 = require("../internal/meta");
function array(type, length, lengthType = 'count') {
if (!util_1.isType(type) && !util_1.isUserType(type)) {
throw new TypeError('Argument #1 should be a valid type.');
}
const isLengthInBytes = lengthType === 'bytes';
const isnum = typeof length === 'number';
const istype = util_1.isType(length);
const isfunc = util_1.isFunction(length);
if (!isnum && !istype && !isfunc) {
throw new TypeError('Unknown type of argument #1.');
}
return {
encode,
decode,
encodingLength,
};
function encode(items, wstream) {
checkArray(items);
const context = meta_1.Metadata.clone(this);
let bytes = 0;
let expectedSize = 0;
if (istype) {
expectedSize = items.length;
}
else if (isnum) {
expectedSize = length;
}
else if (isfunc) {
expectedSize = length(context);
checkArraySizeType(expectedSize);
}
if (!isLengthInBytes) {
checkArraySize(expectedSize, items.length);
}
if (isLengthInBytes) {
const lengthContext = meta_1.Metadata.clone(context);
for (const item of items) {
encoding_length_1.encodingLengthCommon(item, type, lengthContext);
}
if (istype) {
expectedSize = lengthContext.bytes;
}
checkArraySize(lengthContext.bytes, expectedSize);
meta_1.Metadata.clean(lengthContext);
}
if (istype) {
const b = length.encode.call(context, expectedSize, wstream);
bytes += b;
}
items.forEach(item => {
encode_1.encodeCommon(item, wstream, type, context);
});
bytes += context.bytes;
meta_1.Metadata.clean(context);
return bytes;
}
function decode(rstream) {
let expectedSize = 0;
let bytes = 0, count;
const context = meta_1.Metadata.clone(this);
if (isnum) {
expectedSize = length;
}
else if (istype) {
[expectedSize, count] = length.decode.call(context, rstream);
bytes += count;
}
else if (isfunc) {
expectedSize = length(context);
}
checkArraySizeType(expectedSize);
let values;
if (isLengthInBytes) {
values = decodeBytes(type, expectedSize, rstream, context);
}
else {
values = decodeCount(type, expectedSize, rstream, context);
}
bytes += context.bytes;
meta_1.Metadata.clean(context);
return [values, bytes];
}
function encodingLength(items) {
checkArray(items);
const context = meta_1.Metadata.clone(this);
let size = 0;
if (isnum && isLengthInBytes) {
return length;
}
if (istype && !isLengthInBytes) {
size = length.encodingLength(items.length);
}
for (const item of items) {
encoding_length_1.encodingLengthCommon(item, type, context);
}
meta_1.Metadata.clean(context);
size += context.bytes;
if (istype && isLengthInBytes) {
size += length.encodingLength(size);
}
return size;
}
}
exports.array = array;
function checkArray(items) {
if (!Array.isArray(items)) {
throw new TypeError('Argument #1 should be an Array.');
}
}
function checkArraySizeType(length) {
if (typeof length !== 'number') {
throw new TypeError('Length of an array should be a number.');
}
}
function checkArraySize(requiredSize, havingSize) {
if (requiredSize !== havingSize) {
throw new Error(`Argument #1 required length ${requiredSize} instead of ${havingSize}`);
}
}
function decodeBytes(type, lengthBytes, rstream, context) {
const items = [];
const before = context.bytes;
let bytes = 0;
while (bytes < lengthBytes) {
const result = decode_1.decodeCommon(rstream, type, context);
items.push(result);
bytes = context.bytes - before;
}
if (bytes > lengthBytes) {
throw new Error('Incorrect length of an array.');
}
return items;
}
function decodeCount(type, length, rstream, context) {
const items = new Array(length);
for (let i = 0; i < length; i += 1) {
items[i] = decode_1.decodeCommon(rstream, type, context);
}
return items;
}
//# sourceMappingURL=array.js.map