2018-08-22 20:24:32 +01:00
/**
* @author PenguinGeorge [george@penguingeorge.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
2019-07-09 12:23:59 +01:00
import Operation from "../Operation.mjs" ;
import OperationError from "../errors/OperationError.mjs" ;
import Utils from "../Utils.mjs" ;
import { alphabetName , ALPHABET_OPTIONS } from "../lib/Base85.mjs" ;
2018-08-22 20:24:32 +01:00
/**
* From Base85 operation
*/
class FromBase85 extends Operation {
/**
* From Base85 constructor
*/
constructor () {
super ();
this . name = "From Base85" ;
this . module = "Default" ;
2018-08-23 22:05:31 +01:00
this . description = "Base85 (also called Ascii85) is a notation for encoding arbitrary byte data. It is usually more efficient that Base64.<br><br>This operation decodes data from an ASCII string (with an alphabet of your choosing, presets included).<br><br>e.g. <code>BOu!rD]j7BEbo7</code> becomes <code>hello world</code><br><br>Base85 is commonly used in Adobe's PostScript and PDF file formats." ;
2018-08-22 20:24:32 +01:00
this . infoURL = "https://wikipedia.org/wiki/Ascii85" ;
this . inputType = "string" ;
this . outputType = "byteArray" ;
this . args = [
{
name : "Alphabet" ,
type : "editableOption" ,
value : ALPHABET_OPTIONS
},
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {byteArray}
*/
run ( input , args ) {
2018-08-23 22:05:31 +01:00
const alphabet = Utils . expandAlphRange ( args [ 0 ]). join ( "" ),
2018-08-22 20:24:32 +01:00
encoding = alphabetName ( alphabet ),
result = [];
if ( alphabet . length !== 85 ||
[]. unique . call ( alphabet ). length !== 85 ) {
throw new OperationError ( "Alphabet must be of length 85" );
}
if ( input . length === 0 ) return [];
2020-05-16 00:42:31 +02:00
input = input . replace ( /\s+/g , "" );
2018-08-22 20:24:32 +01:00
const matches = input . match ( /<~(.+?)~>/ );
if ( matches !== null ) input = matches [ 1 ];
let i = 0 ;
let block , blockBytes ;
while ( i < input . length ) {
if ( encoding === "Standard" && input [ i ] === "z" ) {
result . push ( 0 , 0 , 0 , 0 );
i ++ ;
} else {
let digits = [];
digits = input
. substr ( i , 5 )
. split ( "" )
. map (( chr , idx ) => {
const digit = alphabet . indexOf ( chr );
if ( digit < 0 || digit > 84 ) {
2018-08-23 22:05:31 +01:00
throw `Invalid character ' ${ chr } ' at index ${ idx } ` ;
2018-08-22 20:24:32 +01:00
}
return digit ;
});
block =
digits [ 0 ] * 52200625 +
digits [ 1 ] * 614125 +
( i + 2 < input . length ? digits [ 2 ] : 84 ) * 7225 +
( i + 3 < input . length ? digits [ 3 ] : 84 ) * 85 +
( i + 4 < input . length ? digits [ 4 ] : 84 );
blockBytes = [
( block >> 24 ) & 0xff ,
( block >> 16 ) & 0xff ,
( block >> 8 ) & 0xff ,
block & 0xff
];
if ( input . length < i + 5 ) {
blockBytes . splice ( input . length - ( i + 5 ), 5 );
}
result . push . apply ( result , blockBytes );
i += 5 ;
}
}
return result ;
}
}
export default FromBase85 ;