WireguardConfigGen/qr/encode.js

176 lines
3.7 KiB
JavaScript

"use strict";
function pushBits(arr, n, value) {
for (var bit = 1 << (n - 1); bit; bit = bit >>> 1) {
arr.push(bit & value ? 1 : 0);
}
}
// {{{1 8bit encode
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;
}
// {{{1 alphanumeric encode
var ALPHANUM = (function (s) {
var res = {};
for (var i = 0; i < s.length; i++) {
res[s[i]] = i;
}
return res;
})('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:');
function encode_alphanum(str) {
var len = str.length;
var bits = [];
for (var i = 0; i < len; i += 2) {
var b = 6;
var n = ALPHANUM[str[i]];
if (str[i + 1]) {
b = 11;
n = n * 45 + ALPHANUM[str[i + 1]];
}
pushBits(bits, b, n);
}
var res = {};
var d = [0, 0, 1, 0];
pushBits(d, 13, len);
res.data27 = d.concat(bits);
if (len < 2048) {
var d = [0, 0, 1, 0];
pushBits(d, 11, len);
res.data10 = d.concat(bits);
}
if (len < 512) {
var d = [0, 0, 1, 0];
pushBits(d, 9, len);
res.data1 = d.concat(bits);
}
return res;
}
// {{{1 numeric encode
function encode_numeric(str) {
var len = str.length;
var bits = [];
for (var i = 0; i < len; i += 3) {
var s = str.substr(i, 3);
var b = Math.ceil(s.length * 10 / 3);
pushBits(bits, b, parseInt(s, 10));
}
var res = {};
var d = [0, 0, 0, 1];
pushBits(d, 14, len);
res.data27 = d.concat(bits);
if (len < 4096) {
var d = [0, 0, 0, 1];
pushBits(d, 12, len);
res.data10 = d.concat(bits);
}
if (len < 1024) {
var d = [0, 0, 0, 1];
pushBits(d, 10, len);
res.data1 = d.concat(bits);
}
return res;
}
// {{{1 url encode
function encode_url(str) {
var slash = str.indexOf('/', 8) + 1 || str.length;
var res = encode(str.slice(0, slash).toUpperCase(), false);
if (slash >= str.length) {
return res;
}
var path_res = encode(str.slice(slash), false);
res.data27 = res.data27.concat(path_res.data27);
if (res.data10 && path_res.data10) {
res.data10 = res.data10.concat(path_res.data10);
}
if (res.data1 && path_res.data1) {
res.data1 = res.data1.concat(path_res.data1);
}
return res;
}
// {{{1 Choose encode mode and generates struct with data for different version
function encode(data, parse_url) {
var str;
var t = typeof data;
if (t == 'string' || t == 'number') {
str = '' + data;
data = Buffer.from(str);
} else if (Buffer.isBuffer(data)) {
str = data.toString();
} else if (Array.isArray(data)) {
data = Buffer.from(data);
str = data.toString();
} else {
throw new Error("Bad data");
}
if (/^[0-9]+$/.test(str)) {
if (data.length > 7089) {
throw new Error("Too much data");
}
return encode_numeric(str);
}
if (/^[0-9A-Z \$%\*\+\.\/\:\-]+$/.test(str)) {
if (data.length > 4296) {
throw new Error("Too much data");
}
return encode_alphanum(str);
}
if (parse_url && /^https?:/i.test(str)) {
return encode_url(str);
}
if (data.length > 2953) {
throw new Error("Too much data");
}
return encode_8bit(data);
}
// {{{1 export functions
module.exports = encode;