282 lines
11 KiB
JavaScript
282 lines
11 KiB
JavaScript
"use strict";
|
|
// Copyright (C) 2016 Dmitry Chestnykh
|
|
// MIT License. See LICENSE file for details.
|
|
var __extends = (this && this.__extends) || (function () {
|
|
var extendStatics = function (d, b) {
|
|
extendStatics = Object.setPrototypeOf ||
|
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
|
return extendStatics(d, b);
|
|
};
|
|
return function (d, b) {
|
|
extendStatics(d, b);
|
|
function __() { this.constructor = d; }
|
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
};
|
|
})();
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
/**
|
|
* Package base64 implements Base64 encoding and decoding.
|
|
*/
|
|
// Invalid character used in decoding to indicate
|
|
// that the character to decode is out of range of
|
|
// alphabet and cannot be decoded.
|
|
var INVALID_BYTE = 256;
|
|
/**
|
|
* Implements standard Base64 encoding.
|
|
*
|
|
* Operates in constant time.
|
|
*/
|
|
var Coder = /** @class */ (function () {
|
|
// TODO(dchest): methods to encode chunk-by-chunk.
|
|
function Coder(_paddingCharacter) {
|
|
if (_paddingCharacter === void 0) { _paddingCharacter = "="; }
|
|
this._paddingCharacter = _paddingCharacter;
|
|
}
|
|
Coder.prototype.encodedLength = function (length) {
|
|
if (!this._paddingCharacter) {
|
|
return (length * 8 + 5) / 6 | 0;
|
|
}
|
|
return (length + 2) / 3 * 4 | 0;
|
|
};
|
|
Coder.prototype.encode = function (data) {
|
|
var out = "";
|
|
var i = 0;
|
|
for (; i < data.length - 2; i += 3) {
|
|
var c = (data[i] << 16) | (data[i + 1] << 8) | (data[i + 2]);
|
|
out += this._encodeByte((c >>> 3 * 6) & 63);
|
|
out += this._encodeByte((c >>> 2 * 6) & 63);
|
|
out += this._encodeByte((c >>> 1 * 6) & 63);
|
|
out += this._encodeByte((c >>> 0 * 6) & 63);
|
|
}
|
|
var left = data.length - i;
|
|
if (left > 0) {
|
|
var c = (data[i] << 16) | (left === 2 ? data[i + 1] << 8 : 0);
|
|
out += this._encodeByte((c >>> 3 * 6) & 63);
|
|
out += this._encodeByte((c >>> 2 * 6) & 63);
|
|
if (left === 2) {
|
|
out += this._encodeByte((c >>> 1 * 6) & 63);
|
|
}
|
|
else {
|
|
out += this._paddingCharacter || "";
|
|
}
|
|
out += this._paddingCharacter || "";
|
|
}
|
|
return out;
|
|
};
|
|
Coder.prototype.maxDecodedLength = function (length) {
|
|
if (!this._paddingCharacter) {
|
|
return (length * 6 + 7) / 8 | 0;
|
|
}
|
|
return length / 4 * 3 | 0;
|
|
};
|
|
Coder.prototype.decodedLength = function (s) {
|
|
return this.maxDecodedLength(s.length - this._getPaddingLength(s));
|
|
};
|
|
Coder.prototype.decode = function (s) {
|
|
if (s.length === 0) {
|
|
return new Uint8Array(0);
|
|
}
|
|
var paddingLength = this._getPaddingLength(s);
|
|
var length = s.length - paddingLength;
|
|
var out = new Uint8Array(this.maxDecodedLength(length));
|
|
var op = 0;
|
|
var i = 0;
|
|
var haveBad = 0;
|
|
var v0 = 0, v1 = 0, v2 = 0, v3 = 0;
|
|
for (; i < length - 4; i += 4) {
|
|
v0 = this._decodeChar(s.charCodeAt(i + 0));
|
|
v1 = this._decodeChar(s.charCodeAt(i + 1));
|
|
v2 = this._decodeChar(s.charCodeAt(i + 2));
|
|
v3 = this._decodeChar(s.charCodeAt(i + 3));
|
|
out[op++] = (v0 << 2) | (v1 >>> 4);
|
|
out[op++] = (v1 << 4) | (v2 >>> 2);
|
|
out[op++] = (v2 << 6) | v3;
|
|
haveBad |= v0 & INVALID_BYTE;
|
|
haveBad |= v1 & INVALID_BYTE;
|
|
haveBad |= v2 & INVALID_BYTE;
|
|
haveBad |= v3 & INVALID_BYTE;
|
|
}
|
|
if (i < length - 1) {
|
|
v0 = this._decodeChar(s.charCodeAt(i));
|
|
v1 = this._decodeChar(s.charCodeAt(i + 1));
|
|
out[op++] = (v0 << 2) | (v1 >>> 4);
|
|
haveBad |= v0 & INVALID_BYTE;
|
|
haveBad |= v1 & INVALID_BYTE;
|
|
}
|
|
if (i < length - 2) {
|
|
v2 = this._decodeChar(s.charCodeAt(i + 2));
|
|
out[op++] = (v1 << 4) | (v2 >>> 2);
|
|
haveBad |= v2 & INVALID_BYTE;
|
|
}
|
|
if (i < length - 3) {
|
|
v3 = this._decodeChar(s.charCodeAt(i + 3));
|
|
out[op++] = (v2 << 6) | v3;
|
|
haveBad |= v3 & INVALID_BYTE;
|
|
}
|
|
if (haveBad !== 0) {
|
|
throw new Error("Base64Coder: incorrect characters for decoding");
|
|
}
|
|
return out;
|
|
};
|
|
// Standard encoding have the following encoded/decoded ranges,
|
|
// which we need to convert between.
|
|
//
|
|
// ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 + /
|
|
// Index: 0 - 25 26 - 51 52 - 61 62 63
|
|
// ASCII: 65 - 90 97 - 122 48 - 57 43 47
|
|
//
|
|
// Encode 6 bits in b into a new character.
|
|
Coder.prototype._encodeByte = function (b) {
|
|
// Encoding uses constant time operations as follows:
|
|
//
|
|
// 1. Define comparison of A with B using (A - B) >>> 8:
|
|
// if A > B, then result is positive integer
|
|
// if A <= B, then result is 0
|
|
//
|
|
// 2. Define selection of C or 0 using bitwise AND: X & C:
|
|
// if X == 0, then result is 0
|
|
// if X != 0, then result is C
|
|
//
|
|
// 3. Start with the smallest comparison (b >= 0), which is always
|
|
// true, so set the result to the starting ASCII value (65).
|
|
//
|
|
// 4. Continue comparing b to higher ASCII values, and selecting
|
|
// zero if comparison isn't true, otherwise selecting a value
|
|
// to add to result, which:
|
|
//
|
|
// a) undoes the previous addition
|
|
// b) provides new value to add
|
|
//
|
|
var result = b;
|
|
// b >= 0
|
|
result += 65;
|
|
// b > 25
|
|
result += ((25 - b) >>> 8) & ((0 - 65) - 26 + 97);
|
|
// b > 51
|
|
result += ((51 - b) >>> 8) & ((26 - 97) - 52 + 48);
|
|
// b > 61
|
|
result += ((61 - b) >>> 8) & ((52 - 48) - 62 + 43);
|
|
// b > 62
|
|
result += ((62 - b) >>> 8) & ((62 - 43) - 63 + 47);
|
|
return String.fromCharCode(result);
|
|
};
|
|
// Decode a character code into a byte.
|
|
// Must return 256 if character is out of alphabet range.
|
|
Coder.prototype._decodeChar = function (c) {
|
|
// Decoding works similar to encoding: using the same comparison
|
|
// function, but now it works on ranges: result is always incremented
|
|
// by value, but this value becomes zero if the range is not
|
|
// satisfied.
|
|
//
|
|
// Decoding starts with invalid value, 256, which is then
|
|
// subtracted when the range is satisfied. If none of the ranges
|
|
// apply, the function returns 256, which is then checked by
|
|
// the caller to throw error.
|
|
var result = INVALID_BYTE; // start with invalid character
|
|
// c == 43 (c > 42 and c < 44)
|
|
result += (((42 - c) & (c - 44)) >>> 8) & (-INVALID_BYTE + c - 43 + 62);
|
|
// c == 47 (c > 46 and c < 48)
|
|
result += (((46 - c) & (c - 48)) >>> 8) & (-INVALID_BYTE + c - 47 + 63);
|
|
// c > 47 and c < 58
|
|
result += (((47 - c) & (c - 58)) >>> 8) & (-INVALID_BYTE + c - 48 + 52);
|
|
// c > 64 and c < 91
|
|
result += (((64 - c) & (c - 91)) >>> 8) & (-INVALID_BYTE + c - 65 + 0);
|
|
// c > 96 and c < 123
|
|
result += (((96 - c) & (c - 123)) >>> 8) & (-INVALID_BYTE + c - 97 + 26);
|
|
return result;
|
|
};
|
|
Coder.prototype._getPaddingLength = function (s) {
|
|
var paddingLength = 0;
|
|
if (this._paddingCharacter) {
|
|
for (var i = s.length - 1; i >= 0; i--) {
|
|
if (s[i] !== this._paddingCharacter) {
|
|
break;
|
|
}
|
|
paddingLength++;
|
|
}
|
|
if (s.length < 4 || paddingLength > 2) {
|
|
throw new Error("Base64Coder: incorrect padding");
|
|
}
|
|
}
|
|
return paddingLength;
|
|
};
|
|
return Coder;
|
|
}());
|
|
exports.Coder = Coder;
|
|
var stdCoder = new Coder();
|
|
function encode(data) {
|
|
return stdCoder.encode(data);
|
|
}
|
|
exports.encode = encode;
|
|
function decode(s) {
|
|
return stdCoder.decode(s);
|
|
}
|
|
exports.decode = decode;
|
|
/**
|
|
* Implements URL-safe Base64 encoding.
|
|
* (Same as Base64, but '+' is replaced with '-', and '/' with '_').
|
|
*
|
|
* Operates in constant time.
|
|
*/
|
|
var URLSafeCoder = /** @class */ (function (_super) {
|
|
__extends(URLSafeCoder, _super);
|
|
function URLSafeCoder() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
// URL-safe encoding have the following encoded/decoded ranges:
|
|
//
|
|
// ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 - _
|
|
// Index: 0 - 25 26 - 51 52 - 61 62 63
|
|
// ASCII: 65 - 90 97 - 122 48 - 57 45 95
|
|
//
|
|
URLSafeCoder.prototype._encodeByte = function (b) {
|
|
var result = b;
|
|
// b >= 0
|
|
result += 65;
|
|
// b > 25
|
|
result += ((25 - b) >>> 8) & ((0 - 65) - 26 + 97);
|
|
// b > 51
|
|
result += ((51 - b) >>> 8) & ((26 - 97) - 52 + 48);
|
|
// b > 61
|
|
result += ((61 - b) >>> 8) & ((52 - 48) - 62 + 45);
|
|
// b > 62
|
|
result += ((62 - b) >>> 8) & ((62 - 45) - 63 + 95);
|
|
return String.fromCharCode(result);
|
|
};
|
|
URLSafeCoder.prototype._decodeChar = function (c) {
|
|
var result = INVALID_BYTE;
|
|
// c == 45 (c > 44 and c < 46)
|
|
result += (((44 - c) & (c - 46)) >>> 8) & (-INVALID_BYTE + c - 45 + 62);
|
|
// c == 95 (c > 94 and c < 96)
|
|
result += (((94 - c) & (c - 96)) >>> 8) & (-INVALID_BYTE + c - 95 + 63);
|
|
// c > 47 and c < 58
|
|
result += (((47 - c) & (c - 58)) >>> 8) & (-INVALID_BYTE + c - 48 + 52);
|
|
// c > 64 and c < 91
|
|
result += (((64 - c) & (c - 91)) >>> 8) & (-INVALID_BYTE + c - 65 + 0);
|
|
// c > 96 and c < 123
|
|
result += (((96 - c) & (c - 123)) >>> 8) & (-INVALID_BYTE + c - 97 + 26);
|
|
return result;
|
|
};
|
|
return URLSafeCoder;
|
|
}(Coder));
|
|
exports.URLSafeCoder = URLSafeCoder;
|
|
var urlSafeCoder = new URLSafeCoder();
|
|
function encodeURLSafe(data) {
|
|
return urlSafeCoder.encode(data);
|
|
}
|
|
exports.encodeURLSafe = encodeURLSafe;
|
|
function decodeURLSafe(s) {
|
|
return urlSafeCoder.decode(s);
|
|
}
|
|
exports.decodeURLSafe = decodeURLSafe;
|
|
exports.encodedLength = function (length) {
|
|
return stdCoder.encodedLength(length);
|
|
};
|
|
exports.maxDecodedLength = function (length) {
|
|
return stdCoder.maxDecodedLength(length);
|
|
};
|
|
exports.decodedLength = function (s) {
|
|
return stdCoder.decodedLength(s);
|
|
};
|
|
//# sourceMappingURL=base64.js.map
|