UNPKG

bali-component-framework

Version:

This library provides a JavaScript based implementation of the Bali Nebula™ Component Framework.

293 lines (263 loc) 10.5 kB
/************************************************************************ * Copyright (c) Crater Dog Technologies(TM). All Rights Reserved. * ************************************************************************ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * * * This code is free software; you can redistribute it and/or modify it * * under the terms of The MIT License (MIT), as published by the Open * * Source Initiative. (See http://opensource.org/licenses/MIT) * ************************************************************************/ 'use strict'; /* * This element class captures the state and methods associated with a * binary string element. */ const moduleName = '/bali/strings/Binary'; const utilities = require('../utilities'); const abstractions = require('../abstractions'); const collections = require('../collections'); // PUBLIC FUNCTIONS /** * This function creates an immutable instance of a binary string using the specified * value. * * An optional debug argument may be specified that controls the level of debugging that * should be applied during execution. The allowed levels are as follows: * <pre> * 0: no debugging is applied (this is the default value and has the best performance) * 1: log any exceptions to console.error before throwing them * 2: perform argument validation checks on each call (poor performance) * 3: log interesting arguments, states and results to console.log * </pre> * * @param {Buffer} value An optional buffer containing the bytes for the binary string. * @param {Object} parameters Optional parameters used to parameterize this element. * @returns {Binary} The new binary string. */ const Binary = function(value, parameters, debug) { abstractions.String.call( this, ['/bali/strings/Binary'], [ '/bali/libraries/Logical', '/bali/libraries/Chainable' ], parameters, debug ); if (this.debug > 1) { this.validateArgument('$Binary', '$value', value, [ '/javascript/Undefined', '/nodejs/Buffer' ]); } // analyze the value value = value || Buffer.alloc(0); // the default value is an empty buffer this.getValue = function() { return Buffer.from(value); }; // make sure it is immutable return this; }; Binary.prototype = Object.create(abstractions.String.prototype); Binary.prototype.constructor = Binary; exports.Binary = Binary; // PUBLIC METHODS /** * This method returns the number of bytes that this binary string has. * * @returns {Number} The number of bytes that this binary string has. */ Binary.prototype.getSize = function() { return this.getValue().length; }; /** * This method returns the byte at the specified index from this binary string. * * @param {Number} index The index of the byte to be retrieved from this binary string. * @returns {Number} The byte value (0..255) at the specified index. */ Binary.prototype.getItem = function(index) { if (this.debug > 1) { this.validateArgument('$getItem', '$index', index, [ '/javascript/Number' ]); } index = abstractions.Component.normalizedIndex(this, index) - 1; // zero-based indexing for JS return this.getValue()[index]; }; /** * This method returns a new binary string containing the bytes associated with the specified indices. * * @param {String|Array|Sequential} indices A sequence of indices specifying which items to be retrieved. * @returns {Binary} A new binary string containing the requested bytes. */ Binary.prototype.getItems = function(indices) { if (this.debug > 1) { this.validateArgument('$getItems', '$indices', indices, [ '/javascript/String', '/javascript/Array', '/bali/interfaces/Sequential' ]); } indices = this.componentize(indices); const buffer = Buffer.alloc(indices.getSize()); var counter = 0; const iterator = indices.getIterator(); while (iterator.hasNext()) { var index = iterator.getNext().toInteger(); index = abstractions.Component.normalizedIndex(this, index); const item = this.getItem(index); buffer[counter++] = item; } return new Binary(buffer, this.getParameters(), this.debug); }; // LOGICAL LIBRARY FUNCTIONS /** * This function returns a new binary string that is the logical NOT of the bits * of the specified binary string. * * @param {Binary} binary The binary value. * @param {Number} debug A number in the range 0..3. * @returns {Binary} The resulting binary. */ Binary.not = function(binary, debug) { if (debug > 1) { abstractions.Component.validateArgument(moduleName, '$not', '$binary', binary, [ '/bali/strings/Binary' ]); } const length = binary.getValue().length; const buffer = Buffer.alloc(length); binary.getValue().forEach(function(byte, index) { buffer[index] = ~byte; }); return new Binary(buffer, binary.getParameters(), debug); }; /** * This function returns a new binary string that is the logical AND of the bits * of the two specified binary strings. * * @param {Binary} first The first binary string. * @param {Binary} second The second binary string. * @param {Number} debug A number in the range 0..3. * @returns {Binary} The resulting binary string. */ Binary.and = function(first, second, debug) { if (debug > 1) { abstractions.Component.validateArgument(moduleName, '$and', '$first', first, [ '/bali/strings/Binary' ]); abstractions.Component.validateArgument(moduleName, '$and', '$second', second, [ '/bali/strings/Binary' ]); } var length = Math.max(first.getValue().length, second.getValue().length); const buffer = Buffer.alloc(length); length = Math.min(first.getValue().length, second.getValue().length); for (var index = 0; index < length; index++) { buffer[index] = first.getValue()[index] & second.getValue()[index]; } return new Binary(buffer, first.getParameters(), debug); }; /** * This function returns a new binary string that is the logical SANS of the bits * of the two specified binary strings. * * @param {Binary} first The first binary string. * @param {Binary} second The second binary string. * @param {Number} debug A number in the range 0..3. * @returns {Binary} The resulting binary string. */ Binary.sans = function(first, second, debug) { if (debug > 1) { abstractions.Component.validateArgument(moduleName, '$sans', '$first', first, [ '/bali/strings/Binary' ]); abstractions.Component.validateArgument(moduleName, '$sans', '$second', second, [ '/bali/strings/Binary' ]); } var length = Math.max(first.getValue().length, second.getValue().length); const buffer = Buffer.alloc(length); length = Math.min(first.getValue().length, second.getValue().length); for (var index = 0; index < length; index++) { buffer[index] = first.getValue()[index] & ~second.getValue()[index]; } return new Binary(buffer, first.getParameters(), debug); }; /** * This function returns a new binary string that is the logical OR of the bits * of the two specified binary strings. * * @param {Binary} first The first binary string. * @param {Binary} second The second binary string. * @param {Number} debug A number in the range 0..3. * @returns {Binary} The resulting binary string. */ Binary.or = function(first, second, debug) { if (debug > 1) { abstractions.Component.validateArgument(moduleName, '$or', '$first', first, [ '/bali/strings/Binary' ]); abstractions.Component.validateArgument(moduleName, '$or', '$second', second, [ '/bali/strings/Binary' ]); } var length = Math.max(first.getValue().length, second.getValue().length); const buffer = Buffer.alloc(length); length = Math.min(first.getValue().length, second.getValue().length); for (var index = 0; index < length; index++) { buffer[index] = first.getValue()[index] | second.getValue()[index]; } return new Binary(buffer, first.getParameters(), debug); }; /** * This function returns a new binary string that is the logical XOR of the bits * of the two specified binary strings. * * @param {Binary} first The first binary string. * @param {Binary} second The second binary string. * @param {Number} debug A number in the range 0..3. * @returns {Binary} The resulting binary string. */ Binary.xor = function(first, second, debug) { if (debug > 1) { abstractions.Component.validateArgument(moduleName, '$xor', '$first', first, [ '/bali/strings/Binary' ]); abstractions.Component.validateArgument(moduleName, '$xor', '$second', second, [ '/bali/strings/Binary' ]); } var length = Math.max(first.getValue().length, second.getValue().length); const buffer = Buffer.alloc(length); length = Math.min(first.getValue().length, second.getValue().length); for (var index = 0; index < length; index++) { buffer[index] = first.getValue()[index] ^ second.getValue()[index]; } return new Binary(buffer, first.getParameters(), debug); }; // CHAINABLE LIBRARY FUNCTIONS /** * This function returns a new binary string that contains the bytes from the second binary * concatenated onto the end of the first binary string. * * @param {List} first The first binary string to be operated on. * @param {List} second The second binary string to be operated on. * @param {Number} debug A number in the range 0..3. * @returns {List} The resulting binary string. */ Binary.chain = function(first, second, debug) { if (debug > 1) { abstractions.Component.validateArgument(moduleName, '$chain', '$first', first, [ '/bali/strings/Binary' ]); abstractions.Component.validateArgument(moduleName, '$chain', '$second', second, [ '/bali/strings/Binary' ]); } const buffer1 = first.getValue(); const buffer2 = second.getValue(); const buffer = Buffer.alloc(buffer1.length + buffer2.length); buffer1.copy(buffer); buffer2.copy(buffer, buffer1.length); return new Binary(buffer, first.getParameters(), debug); };