WireguardConfigGen/qr/qr-base.js

181 lines
5.1 KiB
JavaScript

"use strict";
var encode = require('./encode');
var calculateEC = require('./errorcode');
var matrix = require('./matrix');
function _deepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
}
var EC_LEVELS = ['L', 'M', 'Q', 'H'];
// {{{1 Versions
var versions = [
[], // there is no version 0
// total number of codewords, (number of ec codewords, number of blocks) * ( L, M, Q, H )
[26, 7, 1, 10, 1, 13, 1, 17, 1],
[44, 10, 1, 16, 1, 22, 1, 28, 1],
[70, 15, 1, 26, 1, 36, 2, 44, 2],
[100, 20, 1, 36, 2, 52, 2, 64, 4],
[134, 26, 1, 48, 2, 72, 4, 88, 4], // 5
[172, 36, 2, 64, 4, 96, 4, 112, 4],
[196, 40, 2, 72, 4, 108, 6, 130, 5],
[242, 48, 2, 88, 4, 132, 6, 156, 6],
[292, 60, 2, 110, 5, 160, 8, 192, 8],
[346, 72, 4, 130, 5, 192, 8, 224, 8], // 10
[404, 80, 4, 150, 5, 224, 8, 264, 11],
[466, 96, 4, 176, 8, 260, 10, 308, 11],
[532, 104, 4, 198, 9, 288, 12, 352, 16],
[581, 120, 4, 216, 9, 320, 16, 384, 16],
[655, 132, 6, 240, 10, 360, 12, 432, 18], // 15
[733, 144, 6, 280, 10, 408, 17, 480, 16],
[815, 168, 6, 308, 11, 448, 16, 532, 19],
[901, 180, 6, 338, 13, 504, 18, 588, 21],
[991, 196, 7, 364, 14, 546, 21, 650, 25],
[1085, 224, 8, 416, 16, 600, 20, 700, 25], // 20
[1156, 224, 8, 442, 17, 644, 23, 750, 25],
[1258, 252, 9, 476, 17, 690, 23, 816, 34],
[1364, 270, 9, 504, 18, 750, 25, 900, 30],
[1474, 300, 10, 560, 20, 810, 27, 960, 32],
[1588, 312, 12, 588, 21, 870, 29, 1050, 35], // 25
[1706, 336, 12, 644, 23, 952, 34, 1110, 37],
[1828, 360, 12, 700, 25, 1020, 34, 1200, 40],
[1921, 390, 13, 728, 26, 1050, 35, 1260, 42],
[2051, 420, 14, 784, 28, 1140, 38, 1350, 45],
[2185, 450, 15, 812, 29, 1200, 40, 1440, 48], // 30
[2323, 480, 16, 868, 31, 1290, 43, 1530, 51],
[2465, 510, 17, 924, 33, 1350, 45, 1620, 54],
[2611, 540, 18, 980, 35, 1440, 48, 1710, 57],
[2761, 570, 19, 1036, 37, 1530, 51, 1800, 60],
[2876, 570, 19, 1064, 38, 1590, 53, 1890, 63], // 35
[3034, 600, 20, 1120, 40, 1680, 56, 1980, 66],
[3196, 630, 21, 1204, 43, 1770, 59, 2100, 70],
[3362, 660, 22, 1260, 45, 1860, 62, 2220, 74],
[3532, 720, 24, 1316, 47, 1950, 65, 2310, 77],
[3706, 750, 25, 1372, 49, 2040, 68, 2430, 81] // 40
];
versions = versions.map(function(v, index) {
if (!index) return {};
var res = {
}
for (var i = 1; i < 8; i += 2) {
var length = v[0] - v[i];
var num_template = v[i+1];
var ec_level = EC_LEVELS[(i/2)|0];
var level = {
version: index,
ec_level: ec_level,
data_len: length,
ec_len: v[i] / num_template,
blocks: [],
ec: []
}
for (var k = num_template, n = length; k > 0; k--) {
var block = (n / k)|0;
level.blocks.push(block);
n -= block;
}
res[ec_level] = level;
}
return res;
});
// {{{1 Get version template
function getTemplate(message, ec_level) {
var i = 1;
var len;
if (message.data1) {
len = Math.ceil(message.data1.length / 8);
} else {
i = 10;
}
for (/* i */; i < 10; i++) {
var version = versions[i][ec_level];
if (version.data_len >= len) {
return _deepCopy(version);
}
}
if (message.data10) {
len = Math.ceil(message.data10.length / 8);
} else {
i = 27;
}
for (/* i */; i < 27; i++) {
var version = versions[i][ec_level];
if (version.data_len >= len) {
return _deepCopy(version);
}
}
len = Math.ceil(message.data27.length / 8);
for (/* i */; i < 41; i++) {
var version = versions[i][ec_level];
if (version.data_len >= len) {
return _deepCopy(version);
}
}
throw new Error("Too much data");
}
// {{{1 Fill template
function fillTemplate(message, template) {
var blocks = new Buffer(template.data_len);
blocks.fill(0);
if (template.version < 10) {
message = message.data1;
} else if (template.version < 27) {
message = message.data10;
} else {
message = message.data27;
}
var len = message.length;
for (var i = 0; i < len; i += 8) {
var b = 0;
for (var j = 0; j < 8; j++) {
b = (b << 1) | (message[i + j] ? 1 : 0);
}
blocks[i / 8] = b;
}
var pad = 236;
for (var i = Math.ceil((len + 4) / 8); i < blocks.length; i++) {
blocks[i] = pad;
pad = (pad == 236) ? 17 : 236;
}
var offset = 0;
template.blocks = template.blocks.map(function(n) {
var b = blocks.slice(offset, offset + n);
offset += n;
template.ec.push(calculateEC(b, template.ec_len));
return b;
});
return template;
}
// {{{1 All-in-one
function QR(text, ec_level, parse_url) {
ec_level = EC_LEVELS.indexOf(ec_level) > -1 ? ec_level : 'M';
var message = encode(text, parse_url);
var data = fillTemplate(message, getTemplate(message, ec_level));
return matrix.getMatrix(data);
}
// {{{1 export functions
module.exports = {
QR: QR,
getTemplate: getTemplate,
fillTemplate: fillTemplate,
}