216 líneas
4.3 KiB
JavaScript
216 líneas
4.3 KiB
JavaScript
/*
|
|
Copyright (c) 2011, Chris Umbel
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
*/
|
|
'use strict';
|
|
|
|
var charTable = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
|
var byteTable = [
|
|
0xff,
|
|
0xff,
|
|
0x1a,
|
|
0x1b,
|
|
0x1c,
|
|
0x1d,
|
|
0x1e,
|
|
0x1f,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0x00,
|
|
0x01,
|
|
0x02,
|
|
0x03,
|
|
0x04,
|
|
0x05,
|
|
0x06,
|
|
0x07,
|
|
0x08,
|
|
0x09,
|
|
0x0a,
|
|
0x0b,
|
|
0x0c,
|
|
0x0d,
|
|
0x0e,
|
|
0x0f,
|
|
0x10,
|
|
0x11,
|
|
0x12,
|
|
0x13,
|
|
0x14,
|
|
0x15,
|
|
0x16,
|
|
0x17,
|
|
0x18,
|
|
0x19,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0x00,
|
|
0x01,
|
|
0x02,
|
|
0x03,
|
|
0x04,
|
|
0x05,
|
|
0x06,
|
|
0x07,
|
|
0x08,
|
|
0x09,
|
|
0x0a,
|
|
0x0b,
|
|
0x0c,
|
|
0x0d,
|
|
0x0e,
|
|
0x0f,
|
|
0x10,
|
|
0x11,
|
|
0x12,
|
|
0x13,
|
|
0x14,
|
|
0x15,
|
|
0x16,
|
|
0x17,
|
|
0x18,
|
|
0x19,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0xff
|
|
];
|
|
|
|
function quintetCount(buff) {
|
|
var quintets = Math.floor(buff.length / 5);
|
|
return buff.length % 5 === 0 ? quintets : quintets + 1;
|
|
}
|
|
|
|
exports.bufferToBase32 = function(plain) {
|
|
// plain MUST come in either as Array or Uint8Array
|
|
if ('undefined' !== typeof Uint8Array) {
|
|
if (!(plain instanceof Uint8Array)) {
|
|
plain = new Uint8Array(plain);
|
|
}
|
|
}
|
|
var i = 0;
|
|
var j = 0;
|
|
var shiftIndex = 0;
|
|
var digit = 0;
|
|
var encoded = new Array(quintetCount(plain) * 8);
|
|
|
|
/* byte by byte isn't as pretty as quintet by quintet but tests a bit
|
|
faster. will have to revisit. */
|
|
while (i < plain.length) {
|
|
var current = plain[i];
|
|
|
|
if (shiftIndex > 3) {
|
|
digit = current & (0xff >> shiftIndex);
|
|
shiftIndex = (shiftIndex + 5) % 8;
|
|
digit =
|
|
(digit << shiftIndex) |
|
|
((i + 1 < plain.length ? plain[i + 1] : 0) >> (8 - shiftIndex));
|
|
i++;
|
|
} else {
|
|
digit = (current >> (8 - (shiftIndex + 5))) & 0x1f;
|
|
shiftIndex = (shiftIndex + 5) % 8;
|
|
if (shiftIndex === 0) {
|
|
i++;
|
|
}
|
|
}
|
|
|
|
encoded[j] = charTable[digit];
|
|
j++;
|
|
}
|
|
|
|
for (i = j; i < encoded.length; i++) {
|
|
encoded[i] = '=';
|
|
}
|
|
|
|
return encoded.join('');
|
|
};
|
|
|
|
exports.base32ToBuffer = function(encoded) {
|
|
var shiftIndex = 0;
|
|
var plainDigit = 0;
|
|
var plainChar;
|
|
var plainPos = 0;
|
|
var len = Math.ceil((encoded.length * 5) / 8);
|
|
var decoded;
|
|
encoded = encoded.split('').map(function(ch) {
|
|
return ch.charCodeAt(0);
|
|
});
|
|
if ('undefined' !== typeof Uint8Array) {
|
|
encoded = new Uint8Array(encoded);
|
|
decoded = new Uint8Array(len);
|
|
} else {
|
|
decoded = new Array(len);
|
|
}
|
|
|
|
/* byte by byte isn't as pretty as octet by octet but tests a bit
|
|
faster. will have to revisit. */
|
|
for (var i = 0; i < encoded.length; i++) {
|
|
if (encoded[i] === 0x3d) {
|
|
//'='
|
|
break;
|
|
}
|
|
|
|
var encodedByte = encoded[i] - 0x30;
|
|
|
|
if (encodedByte < byteTable.length) {
|
|
plainDigit = byteTable[encodedByte];
|
|
|
|
if (shiftIndex <= 3) {
|
|
shiftIndex = (shiftIndex + 5) % 8;
|
|
|
|
if (shiftIndex === 0) {
|
|
plainChar |= plainDigit;
|
|
decoded[plainPos] = plainChar;
|
|
plainPos++;
|
|
plainChar = 0;
|
|
} else {
|
|
plainChar |= 0xff & (plainDigit << (8 - shiftIndex));
|
|
}
|
|
} else {
|
|
shiftIndex = (shiftIndex + 5) % 8;
|
|
plainChar |= 0xff & (plainDigit >>> shiftIndex);
|
|
decoded[plainPos] = plainChar;
|
|
plainPos++;
|
|
|
|
plainChar = 0xff & (plainDigit << (8 - shiftIndex));
|
|
}
|
|
} else {
|
|
throw new Error('Invalid input - it is not base32 encoded string');
|
|
}
|
|
}
|
|
|
|
if (decoded.slice) {
|
|
// Array or TypedArray
|
|
return decoded.slice(0, plainPos);
|
|
} else {
|
|
// Mobile Safari TypedArray
|
|
return new Uint8Array(Array.prototype.slice.call(decoded, 0, plainPos));
|
|
}
|
|
};
|