/* Ais payload is represented in a 6bits encoded string !(
This method is a direct transcription in nodejs of C++ ais-decoder code
Danish Maritime Authority AisLib encoding/decoding java library
189749
function AisEncode (msg) {
    this.payload = new Buffer(425); // make a buffer force it 6bit/zero
    this.payload.fill (0x0);        // init to 6bits encoded zero value
    this.payloadSize =0;            // Payload size depend on messages
    this.nmea =[];

    this.PutInt (msg.aistype  ,0,6);
    this.PutInt (msg.repeat   ,6,2);
    this.PutInt (msg.mmsi     ,8,30);
    var lat; var lon; var sog; var hdg; var accuracy; var rot;

    switch (msg.aistype) {
        case 1:
        case 2:
        case 3: // class A position report
            this.class      = 'A';
            this.PutInt(msg.navstatus, 38, 4 );

            // move lat to integer and take care of negative value
            lon = parseInt (msg.lon * 600000);
            if (lon < 0) lon |= 0x08000000;    // on 28 bits
            this.PutInt(lon, 61, 28 );

            lat = parseInt (msg.lat * 600000); // on 27 bits
            if (lat < 0) lat |= 0x04000000;
            this.PutInt(lat, 89, 27 );

            rot=parseInt (msg.rot);  //Rate of turn
            this.PutInt (rot,  42, 8 );

            sog=parseInt (msg.sog *10);  //speed over ground
            this.PutInt (sog,  50, 10 );

            cog=parseInt (msg.cog *10);  //course over ground
            this.PutInt (cog,  116, 12 );

            hdg=parseInt (msg.hdg) || parseInt (msg.cog); //magnetic heading
            this.PutInt (hdg,  128, 9 );

            this.PutInt  (60,  137, 6 );  // 60 if time stamp is not available
            this.PutInt  (msg.smi, 143, 2);

            this.payloadSize=168;   // pad with zero non used flags

            break;
        case 18: // class B position report
            this.class  = 'B';

            sog=parseInt (msg.sog *10);  //speed over ground
            this.PutInt (sog,  46, 10 );

            accuracy= parseInt (msg.accuracy);
            this.PutInt(accuracy, 56, 1 );

            // move lat to integer and take care of negative value
            lon = parseInt (msg.lon * 600000); //Long 1/10000 minute
            if (lon < 0) lon |= 0x08000000;
            this.PutInt(lon, 57, 28 );

            lat = parseInt (msg.lat * 600000); //Lat 1/10000 minute
            if (lat < 0) lat |= 0x04000000;
            this.PutInt(lat, 85, 27 );

            var cog=parseInt (msg.cog *10);  //course over ground
            this.PutInt (cog,  112, 12 );

            hdg=parseInt (msg.hdg)|| parseInt (msg.cog);      //magnetic heading
            this.PutInt (hdg,  124, 9 );

            this.PutInt  (60,  133, 6 );  // 60 [time stamp is not available]

            this.payloadSize=168;   // pad with zero non used flags
            break;
        case 5:
            this.class  = 'A';
//          Get the AIS Version indicator
//          0 = station compliant with Recommendation ITU-R M.1371-1
//          1 = station compliant with Recommendation ITU-R M.1371-3
//          2-3 = station compliant with future editions

            this.PutInt (1,38, 2); // version station =1
            this.PutInt (msg.imo     ,40, 30);
            this.PutStr (msg.callsign,70, 42);
            this.PutStr (msg.shipname,112, 120);
            this.PutInt (msg.cargo   ,232, 8);
            this.PutInt (msg.dimA    ,240, 9);
            this.PutInt (msg.dimB    ,249, 9);
            this.PutInt (msg.dimC    ,258, 6);
            this.PutInt (msg.dimD    ,264, 6);
            this.PutInt (msg.etaMo   ,274, 4);
            this.PutInt (msg.etaDay  ,278, 5);
            this.PutInt (msg.etaHr   ,283, 5);
            this.PutInt (msg.etaMin  ,288, 6);
            var draught = parseInt (msg.draught*10);
            this.PutInt((parseInt(draught*10)), 294, 8);
            this.PutStr(msg.destination,302,120);
            this.payloadSize=422;
            break;
      
        case 21:
            this.PutInt(msg.aid_type, 38, 5);
            this.PutStr(msg.atonname, 43, 120);
            accuracy= parseInt (msg.accuracy);
            this.PutInt(accuracy,     163, 1);
      
            lon = parseInt (msg.lon * 600000); //Long 1/10000 minute
            if (lon < 0) lon |= 0x08000000;
            this.PutInt(lon, 164, 28 );
      
            lat = parseInt (msg.lat * 600000); //Lat 1/10000 minute
            if (lat < 0) lat |= 0x04000000;
            this.PutInt(lat, 192, 27 );

            this.PutInt (msg.dimA     ,219, 9);
            this.PutInt (msg.dimB     ,228, 9);
            this.PutInt (msg.dimC     ,237, 6);
            this.PutInt (msg.dimD     ,243, 6);

            this.PutInt (60           ,253, 6 ); // 60 if time stamp is not available
            this.PutInt (msg.off_position, 259, 1);
            this.PutInt (msg.raim     ,268, 1);
            this.PutInt (msg.virtual_aid, 269, 1);
            this.PutInt (msg.assigned ,270, 1);
            break;
      
        case 24:  // Vesel static information
            this.class='B';
            this.PutInt(msg.part, 38, 2 );
            if (msg.part===0) {
                this.PutStr(msg.shipname, 40, 120);
                this.payloadSize=160;
            } else if ( msg.part === 1) {
                this.PutInt(msg.cargo   , 40, 8 );
                this.PutStr(msg.callsign, 90, 42);
                this.PutInt (msg.dimA, 132, 9 );
                this.PutInt (msg.dimB, 141, 9 );
                this.PutInt (msg.dimC, 150, 6 );
                this.PutInt (msg.dimD, 156, 6 );
                this.payloadSize=168; // ignore last flags
            } else {
                // message part missing
                this.valid=false;
            }
            break;
        case 25:  // single slot Binary message
            this.class='B';
            this.PutInt(1, 38, 1 ); // single destination
            this.PutInt(msg.mmsi   , 40, 20 ); // we self ping only
            this.payloadSize=168; // ignore last flags
            break;
        default:
            // not implemented
            this.valid=false;
            return;
    }

    // Make sure we finish on a byte boundary
    var size= parseInt(this.payloadSize/6);
    if (this.payloadSize%6 > 0) size++;
    for(var i = 0; i < size ; i++) {
        var chr = this.payload[i];

        // move to printable char from wacky AIS/IEC 6 bit representation
        if (chr < 40) {
            this.payload[i] = chr +48;
        } else {
            this.payload[i] = chr +56;
        }
    }

    // Finish nmea message !AIVDM,1,1,,B,B69>7mh0?J<:>05B0`0e;wq2PHI8,0*3D'
    // this.fragcnt = nmea[1];  // fragment total count for this message
    // this.fragnum = nmea[2];  // fragment number
    // this.fragid  = nmea[3];  // fragment sequential index for multipart message
    // this.pading  = nmea[6].split ('*')[0];
    var nmea=[];
    nmea [0] = '!AIVDM';  // ! is added after checksum
    nmea [1]  = '1';      // ignore multipart extention messages
    nmea [2]  = '1';
    nmea [3]  = '';
    nmea [4]  = 'A';     // this is VHF channel and not AIS class
    nmea [5]  = this.payload.toString("utf8", 0, size);
    nmea [6]  = 0;
    var paquet = nmea.toString();

    var checksum = 0; // http://rietman.wordpress.com/2008/09/25/how-to-calculate-the-nmea-checksum/
    for(var i = 1; i < paquet.length; i++) {
        checksum = checksum ^ paquet.charCodeAt(i);
    }

    var trailer;
    if (checksum < 16)  trailer= "*0" + checksum.toString(16).toUpperCase();
    else trailer= "*" + checksum.toString(16).toUpperCase();

    this.nmea =  paquet + trailer;
    this.valid=  true;
}
320823
function _decodeBlob(encodedBlob) {
    var arrayBuff = _binStringToArrayBuffer(atob(encodedBlob.data));
    return createBlob([arrayBuff], { type: encodedBlob.type });
}
457416
function _decodeBlob(encodedBlob) {
	        var arrayBuff = _binStringToArrayBuffer(atob(encodedBlob.data));
	        return _createBlob([arrayBuff], { type: encodedBlob.type });
	    }
248046
function decodeCryptojsSalt (input) {
  var ciphertext = Buffer.from(input, 'base64')
  if (ciphertext.slice(0, 8).toString() === 'Salted__') {
    return {
      salt: ciphertext.slice(8, 16),
      ciphertext: ciphertext.slice(16)
    }
  } else {
    return {
      ciphertext: ciphertext
    }
  }
}
783745
function bytesToString(arr) {
    if (arr instanceof ArrayBuffer) {
        arr = new Uint8Array(arr);
    }
    return textDecoder.decode(arr);
}
1370989
public void decode(AsnInputStream ais) throws ParseException {

        this.correlationId = null;
        this.rejectProblem = null;
        this.localOriginated = false;

        try {
            AsnInputStream localAis = ais.readSequenceStream();

            // correlationId
            byte[] buf = TcapFactory.readComponentId(localAis, 0, 1);
            if (buf.length > 0)
                this.setCorrelationId((long) buf[0]);

            // rejectProblem
            int tag = localAis.readTag();
            if (tag != Reject._TAG_REJECT_PROBLEM || localAis.getTagClass() != Tag.CLASS_PRIVATE
                    || !localAis.isTagPrimitive()) {
                throw new ParseException(RejectProblem.generalIncorrectComponentPortion,
                        "RejectProblem in Reject has bad tag or tag class or is not primitive: tag=" + tag + ", tagClass=" + localAis.getTagClass());
            }
            long i1 = localAis.readInteger();
            this.rejectProblem = RejectProblem.getFromInt(i1);

            // Empty parameter
            // we do not parse an empty parameter because it is useless

        } catch (IOException e) {
            throw new ParseException(RejectProblem.generalBadlyStructuredCompPortion, "IOException while decoding Reject: " + e.getMessage(), e);
        } catch (AsnException e) {
            throw new ParseException(RejectProblem.generalBadlyStructuredCompPortion, "AsnException while decoding Reject: " + e.getMessage(), e);
        }
    }
42826
async function decryptPBES2(decoded, passphrase){
  const kdf = decoded.encryptionAlgorithm.parameters.keyDerivationFunc;
  const eS = decoded.encryptionAlgorithm.parameters.encryptionScheme;

  // pbkdf2
  const keyLength = params.encryptionSchemes[eS.algorithm].keyLength; // get keyLength
  let key;
  if(kdf.algorithm === 'pbkdf2') {
    const pBuffer = jseu.encoder.stringToArrayBuffer(passphrase);
    if (kdf.parameters.salt.type !== 'specified') throw new Error('UnsupportedSaltSource');
    const salt = new Uint8Array(kdf.parameters.salt.value);
    const iterationCount = kdf.parameters.iterationCount.toNumber();
    const prf = kdf.parameters.prf.algorithm;
    key = await pbkdf.pbkdf2(pBuffer, salt, iterationCount, keyLength, params.pbkdf2Prfs[prf].hash);
  }
  else throw new Error('UnsupportedKDF');

  // decryption
  // TODO other encryption schemes
  let out;
  if(eS.algorithm === 'des-ede3-cbc'){
    const iv = eS.parameters;
    const CBC = des.CBC.instantiate(des.EDE);
    const pt = CBC.create({ type: 'decrypt', key, iv });
    out = Buffer.from(pt.update(decoded.encryptedData).concat(pt.final()));
  }
  else if (eS.algorithm === 'aes128-cbc' || eS.algorithm === 'aes192-cbc'|| eS.algorithm === 'aes256-cbc'){
    const iv = new Uint8Array(eS.parameters);
    out = Buffer.from( await jscaes.decrypt(
      new Uint8Array(decoded.encryptedData), key, {name: 'AES-CBC', iv}
    ));
  } else throw new Error('UnsupportedEncryptionAlgorithm');

  return OneAsymmetricKey.decode(out, 'der');
}
14253
function decode(base64string) {
        var number = 0;
        var chars = base64string.split('');
        var len = chars.length;
        var val10;
        var val64;
        var asciiVal;

        for (var i = 0; i < len; i++) {

            val64 = chars[len - 1 - i];
            asciiVal = val64.charCodeAt(0);
            val10 = 0;
            if (val64 === '_') {
                val10 = 63;
            }
            else if (val64 === '-') {
                val10 = 62;
            }
            else if (asciiVal > 96 && asciiVal < 123) {
                val10 = asciiVal - 61;
            }
            else if (asciiVal > 64 && asciiVal < 91) {
                val10 = asciiVal - 55;
            }
            else if (asciiVal > 47 && asciiVal < 58) {
                val10 = asciiVal - 48;
            }
            else {
                throw new AppError({ msg: 'Non-base64value in encoded string' });
            }

            number += (Math.pow(64, i) * val10);
        }

        return number;
    }
478915
public void decode(AsnInputStream ais) throws ParseException {

        try {
            this.setLocalOriginated(false);

            AsnInputStream localAis = ais.readSequenceStream();

            int tag = localAis.readTag();
            if (localAis.getTagClass() != Tag.CLASS_UNIVERSAL) {
                throw new ParseException(null, GeneralProblemType.MistypedComponent,
                        "Error while decoding Reject: bad tag class for InvokeID or NULL: tagClass = " + localAis.getTagClass());
            }
            switch (tag) {
                case _TAG_IID:
                    this.invokeId = localAis.readInteger();
                    break;
                case Tag.NULL:
                    localAis.readNull();
                    break;
            }

            tag = localAis.readTag();
            if (localAis.getTagClass() != Tag.CLASS_CONTEXT_SPECIFIC) {
                throw new ParseException(null, GeneralProblemType.MistypedComponent,
                        "Error while decoding Reject: bad tag class for a problem: tagClass = " + localAis.getTagClass());
            }
            ProblemType pt = ProblemType.getFromInt(tag);
            if (pt == null) {
                throw new ParseException(null, GeneralProblemType.MistypedComponent,
                        "Error while decoding Reject: ProblemType not found");
            }
            this.problem = TcapFactory.createProblem(pt, localAis);

        } catch (IOException e) {
            throw new ParseException(null, GeneralProblemType.BadlyStructuredComponent, "IOException while decoding Reject: "
                    + e.getMessage(), e);
        } catch (AsnException e) {
            throw new ParseException(null, GeneralProblemType.BadlyStructuredComponent, "AsnException while decoding Reject: "
                    + e.getMessage(), e);
        }

    }
811857
public void decode(AsnInputStream ais) throws ParseException {
        try {
            tag = ais.getTag();
            primitive = ais.isTagPrimitive();
            tagClass = ais.getTagClass();
            data = ais.readSequence();
            this.encodingLength = data.length;
            if (singleParameterInAsn && ais.available() > 0) { // extra data found after main array
                byte[] buf = new byte[data.length + ais.available()];
                System.arraycopy(data, 0, buf, 0, data.length);
                ais.read(buf, data.length, ais.available());
                data = buf;
            }

        } catch (IOException e) {
            throw new ParseException(RejectProblem.generalBadlyStructuredCompPortion, "IOException while decoding the parameter: " + e.getMessage(), e);
        } catch (AsnException e) {
            throw new ParseException(RejectProblem.generalBadlyStructuredCompPortion, "AsnException while decoding the parameter: " + e.getMessage(), e);
        }
    }
3530
function() {

    var _buffer = 0;
    var _buflen = 0;
    var _length = 0;
    var _base64 = '';

    var _this = {};

    var writeEncoded = function(b) {
      _base64 += String.fromCharCode(encode(b & 0x3f) );
    };

    var encode = function(n) {
      if (n < 0) {
        // error.
      } else if (n < 26) {
        return 0x41 + n;
      } else if (n < 52) {
        return 0x61 + (n - 26);
      } else if (n < 62) {
        return 0x30 + (n - 52);
      } else if (n == 62) {
        return 0x2b;
      } else if (n == 63) {
        return 0x2f;
      }
      throw 'n:' + n;
    };

    _this.writeByte = function(n) {

      _buffer = (_buffer << 8) | (n & 0xff);
      _buflen += 8;
      _length += 1;

      while (_buflen >= 6) {
        writeEncoded(_buffer >>> (_buflen - 6) );
        _buflen -= 6;
      }
    };

    _this.flush = function() {

      if (_buflen > 0) {
        writeEncoded(_buffer << (6 - _buflen) );
        _buffer = 0;
        _buflen = 0;
      }

      if (_length % 3 != 0) {
        // padding
        var padlen = 3 - _length % 3;
        for (var i = 0; i < padlen; i += 1) {
          _base64 += '=';
        }
      }
    };

    _this.toString = function() {
      return _base64;
    };

    return _this;
  }
1082724
public int encodeDigits(ByteArrayOutputStream bos) {
        boolean isOdd = this.oddFlag == _FLAG_ODD;

        byte b = 0;
        int count = (!isOdd) ? address.length() : address.length() - 1;
        int bytesCount = 0;
        for (int i = 0; i < count - 1; i += 2) {
            String ds1 = address.substring(i, i + 1);
            String ds2 = address.substring(i + 1, i + 2);

            int d1 = Integer.parseInt(ds1, 16);
            int d2 = Integer.parseInt(ds2, 16);

            b = (byte) (d2 << 4 | d1);
            bos.write(b);
            bytesCount++;
        }

        if (isOdd) {
            String ds1 = address.substring(count, count + 1);
            int d = Integer.parseInt(ds1);

            b = (byte) (d & 0x0f);
            bos.write(b);
            bytesCount++;
        }

        return bytesCount;
    }
914122
public void decode(AsnInputStream ais) throws ParseException {

        try {
            AsnInputStream localAis = ais.readSequenceStream();

            int tag = localAis.readTag();
            if (tag != Tag.EXTERNAL || localAis.getTagClass() != Tag.CLASS_UNIVERSAL)
                throw new AsnException("Error decoding UserInformation.sequence: wrong tag or tag class: tag=" + tag
                        + ", tagClass=" + localAis.getTagClass());

            ext.decode(localAis);
        } catch (IOException e) {
            throw new ParseException(PAbortCauseType.BadlyFormattedTxPortion, null,
                    "IOException when decoding UserInformation: " + e.getMessage(), e);
        } catch (AsnException e) {
            throw new ParseException(PAbortCauseType.BadlyFormattedTxPortion, null,
                    "AsnException when decoding UserInformation: " + e.getMessage(), e);
        }
    }
762448
function decodeArrayToStringUtf8 (a) {
  // FIXME: give this some more testing (i.e. inside gblock component)
  // Avoid the String.fromCharCode.apply(null, array) shortcut, which
  // throws a "maximum call stack size exceeded" error for large arrays.
  for (var i = 0, l = a.length, s = ''; i < l; i++) s += String.fromCharCode(a[i])
  return s
}
41026
@VisibleForTesting
	static byte[] ascii8To6bitBin(byte[] toDecBytes) {

		byte[] convertedBytes = new byte[toDecBytes.length];
		int sum = 0;
		int _6bitBin = 0;

		for (int i = 0; i < toDecBytes.length; i++) {
			sum = 0;
			_6bitBin = 0;

			if (toDecBytes[i] < 48) {
				throw new AisParseException(AisParseException.INVALID_CHARACTER + " "
				        + (char) toDecBytes[i]);
			} else {
				if (toDecBytes[i] > 119) {
					throw new AisParseException(AisParseException.INVALID_CHARACTER + " "
					        + (char) toDecBytes[i]);
				} else {
					if (toDecBytes[i] > 87) {
						if (toDecBytes[i] < 96) {
							throw new AisParseException(AisParseException.INVALID_CHARACTER + " "
							        + (char) toDecBytes[i]);
						} else {
							sum = toDecBytes[i] + 40;
						}
					} else {
						sum = toDecBytes[i] + 40;
					}
					if (sum != 0) {
						if (sum > 128) {
							sum += 32;
						} else {
							sum += 40;
						}
						_6bitBin = sum & 0x3F;
						convertedBytes[i] = (byte) _6bitBin;
					}
				}
			}
		}

		return convertedBytes;
	}
1302971
function _emsa_pss_encode($m, $emBits)
    {
        // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
        // be output.

        $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
        $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;

        $mHash = $this->hash->hash($m);
        if ($emLen < $this->hLen + $sLen + 2) {
            user_error('Encoding error');
            return false;
        }

        $salt = Random::string($sLen);
        $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
        $h = $this->hash->hash($m2);
        $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
        $db = $ps . chr(1) . $salt;
        $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
        $maskedDB = $db ^ $dbMask;
        $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
        $em = $maskedDB . $h . chr(0xBC);

        return $em;
    }
1163397
function encode_8bit(data) {
    var len = data.length;
    var bits = [];

    for (var i = 0; i < len; i++) {
        pushBits(bits, 8, data[i]);
    }

    var res = {};

    var d = [0, 1, 0, 0];
    pushBits(d, 16, len);
    res.data10 = res.data27 = d.concat(bits);

    if (len < 256) {
        var d = [0, 1, 0, 0];
        pushBits(d, 8, len);
        res.data1 = d.concat(bits);
    }

    return res;
}