lib-utils-ts
Version:
<img src="https://img.shields.io/npm/v/lib-utils-ts"/> <img src="https://img.shields.io/snyk/vulnerabilities/npm/lib-utils-ts"/> <img src="https://img.shields.io/npm/l/lib-utils-ts"/> <img src="https://img.shields.io/github/languages/top/devGnode/lib-util
377 lines (347 loc) • 13.7 kB
text/typescript
import {ConsumerResult, convert} from "./Globals";
import {PrimitiveNumber} from "./PrimitiveNumber";
import {IOException, RuntimeException} from "../Exception";
import {Objects} from "../type/Objects";
import {Encoder} from "../file/charset/Encoder";
import {Types} from "./Types";
/***
* @Convert: Public abstract class
* @ConvertConsumer
* @ConvertConsumerRoundedHex
* @ConvertConsumerRounded
* @ConvertConsumerRoundedHex
* @ConvertHexBinaryConsumer
* @ConvertIntToStr
*/
export enum ENDIAN {
BIG = 0x00,
LITTLE = 0x01
}
export abstract class Convert{
/***
* Constant
*/
public static readonly BIN:number = 0x02;
public static readonly HEX:number = 0x10;
public static readonly OCT:number = 0x08;
//
public static readonly NO:number = 0x00;
public static readonly RD:number = 0x01;
public static readonly X2:number = Convert.NO;
public static readonly UPPER:number = 0x02;
//
public static readonly BIG_ENDIAN:number = ENDIAN.BIG;
public static readonly LITTLE_ENDIAN:number = ENDIAN.LITTLE;
/***
* @convert
*/
protected static convert( value:number, base:number, consumer:ConsumerResult<number,string> ): ConsumerResult<number,string>{
let t:number = 0;
if(value<0) throw new IOException(`value is a negative number : only an absolute value number can be converted`);
try{
if( value === 0 ) consumer.accept( 0);
while( Math.floor( value ) > 0 ){
t = Math.floor( value%base );
value/= base;
consumer.accept(t);
}
}catch(e){throw new RuntimeException(e);}
return consumer;
}
/***
* @reversedToNumber
*/
protected static reversed<T>( value:T[], radix:number, action:ConsumerResult<T,number>):number{
let out:number = 0, len:number = value.length,
i:number = len-1, accepted:number;
for (; i >= 0; --i) {
if (!Objects.isNull(accepted = <number>action.accept(value[(len - 1) - i]))) {
out += radix.equals(2) ? Math.pow(radix, i) :
accepted * Math.pow(radix, i);
}
}
return out;
}
/***
* @ConvertConsumer: void consumer ready to convert.
*
*/
private static ConvertConsumer = class ConvertConsumer implements ConsumerResult<number,string>{
protected value:string = "";
accept(a: number): void{this.value += String(a);}
get( ):string{return this.value.split("").reverse().join("");}
clear():void {this.value=""}
protected static round( value: string, sizeOf:number = null):string{
return value.length< sizeOf && sizeOf-value.length>0 ?
String.repeatString("0",Math.abs(sizeOf-value.length))+value :
value;
}
}
/***
* @ConvertHexConsumer: made a concat for hex values
*/
private static ConvertHexConsumer = class ConvertHexConsumer extends Convert.ConvertConsumer implements ConsumerResult<number,string>{
/***
* @override
*/
accept(a:number): void{this.value += a < 10 ? String(a) : ("abcdef")[ a-10 ];}
}
/***
* @ConvertConsumerRounded: void consumer
*
* @option "NO" for none will be return a value not round,
* 2 Bytes number 27 dec => 1B hex.
*
* @options "X2" allows to convert all these bytes correctly
* in String value should must to rounded for have a good
* value "\xFF\xFF" not "\xFF".
*
*/
private static ConvertConsumerRounded = class ConvertConsumerRounded
extends Convert.ConvertConsumer
implements ConsumerResult<number,string>{
public static readonly NO:number = Convert.NO;
public static readonly X2:number = Convert.X2;
public static readonly UPPER:number = Convert.UPPER;
protected readonly characteristics:number;
protected readonly sizeof:number;
constructor(opts:number = 0x00, sizeof:number) {
super();
this.characteristics = opts;
this.sizeof = sizeof;
}
/***
* @override
*/
get( ):string{
let value:string =
!(this.characteristics&0x1) ? super.get().replace(/^0*/,"")
: Convert.ConvertConsumerRounded.round(super.get(),this.sizeof.equals(1)? 2 : this.sizeof);
return ((this.characteristics&0x2) >> 1) ? value.toUpperCase() : value;
}
}
/***
* @ConvertConsumerRoundedHex
*/
private static ConvertConsumerRoundedHex = class ConvertHexBinaryConsumer
extends Convert.ConvertConsumerRounded
implements ConsumerResult<number,string>{
constructor(opts:number = Convert.X2, sizeof:number) {super(opts, sizeof*2);}
/***
* @override
*/
accept(a: number): void{this.value += a < 10 ? String(a) : ("abcdef")[ a-10 ];}
}
/***
* @ConvertHexBinaryConsumer:
*
*/
private static ConvertHexBinaryConsumer = class ConvertHexBinaryConsumer
extends Convert.ConvertConsumerRounded
implements ConsumerResult<number,string>{
constructor(opts:number = Convert.X2, sizeof:number) {super(opts, sizeof*2);}
/***
* @override
*/
accept(a: number) {this.value += ConvertHexBinaryConsumer.round(Convert.To.hex(a));}
}
/***
* @ConvertBinConsumer
*/
private static ConvertBinConsumer = class ConvertBinConsumer
extends Convert.ConvertConsumerRounded
implements ConsumerResult<number,string>{
constructor(opts:number = Convert.RD, sizeof:number) {super(opts, sizeof);}
/***
* @override
*/
get( ):string{
return !(this.characteristics&0x1) ?
super.get().replace(/^0*/,"") :
Convert.ConvertConsumerRounded.round(super.get(),this.sizeof*8);
}
}
/***
* @ConvertIntToStr
*/
private static ConvertIntToStr = class ConvertIntStr
extends Convert.ConvertConsumer
implements ConsumerResult<number,string>{
protected readonly characteristics:number;
protected readonly sizeOf:number;
constructor(opts:number, sizeOf: number ) {
super();
this.characteristics = opts;
this.sizeOf = sizeOf;
}
/***
* @override
*/
accept(a: number) {this.value += Encoder.from("ISO-8851-1").encode(a);}
/***
* @param c
* @return {string}
*/
bound(c:number):string{return c<0 ? "" : String.repeatString("\x00", c);}
/***
* @override
*/
get(): string {return this.bound(this.sizeOf - this.value.length) + (this.characteristics.equals(ENDIAN.BIG) ? super.get() : this.value);}
}
/***
* @UnConvertConsumer
*/
private static UnConvertConsumer = class UnConvertConsumer implements ConsumerResult<string,number>{
protected value:number = 0;
accept(value: string): number{
if(isNaN(parseInt(value))) throw new IOException(`Bad numeric value : ${value}`);
return parseInt(value);
}
get( ):number{return this.value;}
clear():void {this.value=0;}
}
/***
* @Convert.To: Exported class access via Convert.To
*/
public static To = new class To implements convert{
/***
* @Convert.To: binary, value should be less than 0x00FFFFFFFFFFFF
* and equals pr greater than 0.
*
* @IOException
* if is a negative number cast it in unsigned number
*/
public bin(value:number):string{return Convert.convert(Objects.requireNotNull(value), Convert.BIN, new Convert.ConvertConsumer() ).get();}
/***
* @Convert.To: octal
* @IOException
* if is a negative number cast it in unsigned number
*/
public octal(value:number):string{return Convert.convert(Objects.requireNotNull(value), Convert.OCT, new Convert.ConvertConsumer() ).get();}
/***
* @Convert.To: hex
* @IOException
* if is a negative number cast it in unsigned number
*/
public hex(value:number):string{return Convert.convert(Objects.requireNotNull(value), Convert.HEX, new Convert.ConvertHexConsumer() ).get();}
/***
* @binBinary
* @IOException
*/
public binBinary(value:number, sizeof:number, opts:number= Convert.RD ):string{
return Convert.convert(Objects.requireNotNull(value), Convert.BIN, new Convert.ConvertBinConsumer( opts, Objects.requireNotNull(sizeof) ) ).get();
}
/***
* @Convert.To: hexBinary
* @IOException
* Allows to convert a positive or a negative number.
* limit 32bits
*/
public hexBinary(value:number, sizeof:number, opts:number= Convert.RD ):string{
Objects.requireNotNull(value);
if(value<0){
let i:number=0, slice:number[], tmp: ConsumerResult<number,string>;
tmp = new Convert.ConvertHexBinaryConsumer(opts,Objects.requireNotNull(sizeof));
slice = PrimitiveNumber.slice32(value).reverse();
do{tmp.accept(slice[i]);}while (slice[i++]&&i<sizeof);
return tmp.get();
}
return Convert.convert(value, Convert.HEX, new Convert.ConvertConsumerRoundedHex(opts,sizeof)).get();
}
/***
* @int2Str
* @IOException
* @opts 0 = BIG_ENDIAN ; 1 = LITTLE_ENDIAN
* I have found this way, most quickly than old limited
* method with the bitwise operators it was been limited
* in 32 bits values.
*/
public int2Str( value:number, sizeof:number = null, opts:ENDIAN = Convert.BIG_ENDIAN ):string{
return Convert.convert(Objects.requireNotNull(value), Types.BYTE.getLimit() + 1, new Convert.ConvertIntToStr(opts, sizeof) ).get();
}
/****
* @base
* @IOException
*/
public base(value:number, radix:number, consumer:ConsumerResult<number,string>):string{
return Convert.convert(Objects.requireNotNull(value), Objects.requireNotNull(radix), consumer ).get();
}
/***
* @binToNumber
*/
public binToNumber(value:string):number{
return Convert.reversed(Objects.requireNotNull(value).split(''), Convert.BIN, new class extends Convert.UnConvertConsumer implements ConsumerResult<string, number>{
/***
* @override
*/
accept(o: string): number {
let v:number;
if( (v = super.accept(o)) < 0 || v > 1 ) throw new IOException(`Bad input binary value : ${o}`);
return v.equals(0) ? null : 0;
}
});
}
/***
* @binToNumber
*/
public hexToNumber(value:string):number{
return Convert.reversed(Objects.requireNotNull(value).split(''), Convert.HEX, new class extends Convert.UnConvertConsumer implements ConsumerResult<string, number>{
/***
* @override
*/
accept(o: string): number {
let value:number;
if(isNaN(parseInt(o = o.toLowerCase()))){
if( ( value = ["a","b","c","d","e","f"].indexOf(o)) === -1) throw new IOException(`Bad hexadecimal format [0-9A-F] : ${o}`);
return value + 10;
}
return parseInt(o);
}
});
}
/***
* @binToNumber
*/
public octalStringToNumber(value:string):number{
return Convert.reversed(Objects.requireNotNull(value).split(''), Convert.HEX, new Convert.UnConvertConsumer());
}
/***
* @binToNumber
* @param value: String
* This method return a unsigned number
* 0 >= x <= 0x07FFFFFFFFFFFFFF
*/
public strToNumber(value:string):number{
return Convert.reversed(Objects.requireNotNull(value).split(''), Types.BYTE.getLimit() + 1, new class extends Convert.UnConvertConsumer implements ConsumerResult<string, number>{
/***
* @override
*/
accept(o: string): number {
let v:number;
if( ( v = o.charCodeAt(0) ) < 0 && v > 0xFF ) throw new IOException(`Bad encoding use a binary buffer ISO/CEI 8859-1`);
return v;
}
});
}
}
/**
* @arrayToNumber
* @param value: Byte array
* This method return a unsigned number
* 0 >= x <= 0x07FFFFFFFFFFFFFF
*/
public static arrayToNumber(value:number[]):number{
return Convert.reversed(Objects.requireNotNull(value), Types.BYTE.getLimit() + 1, new class implements ConsumerResult<number, number>{
/***
* @override
*/
accept(o: number): number {
if( o < 0 && o > 0xFF ) throw new IOException(`Bad encoding use a binary buffer ISO/CEI 8859-1`);
return o;
}
clear(): void {}
get(): number {return undefined;}
});
}
}
Object.package(this);