168 lines
3.9 KiB
JavaScript
168 lines
3.9 KiB
JavaScript
const VersionCheck = require('./version-check')
|
|
const Regex = require('./regex')
|
|
|
|
/**
|
|
* Numeric mode encodes data from the decimal digit set (0 - 9)
|
|
* (byte values 30HEX to 39HEX).
|
|
* Normally, 3 data characters are represented by 10 bits.
|
|
*
|
|
* @type {Object}
|
|
*/
|
|
exports.NUMERIC = {
|
|
id: 'Numeric',
|
|
bit: 1 << 0,
|
|
ccBits: [10, 12, 14]
|
|
}
|
|
|
|
/**
|
|
* Alphanumeric mode encodes data from a set of 45 characters,
|
|
* i.e. 10 numeric digits (0 - 9),
|
|
* 26 alphabetic characters (A - Z),
|
|
* and 9 symbols (SP, $, %, *, +, -, ., /, :).
|
|
* Normally, two input characters are represented by 11 bits.
|
|
*
|
|
* @type {Object}
|
|
*/
|
|
exports.ALPHANUMERIC = {
|
|
id: 'Alphanumeric',
|
|
bit: 1 << 1,
|
|
ccBits: [9, 11, 13]
|
|
}
|
|
|
|
/**
|
|
* In byte mode, data is encoded at 8 bits per character.
|
|
*
|
|
* @type {Object}
|
|
*/
|
|
exports.BYTE = {
|
|
id: 'Byte',
|
|
bit: 1 << 2,
|
|
ccBits: [8, 16, 16]
|
|
}
|
|
|
|
/**
|
|
* The Kanji mode efficiently encodes Kanji characters in accordance with
|
|
* the Shift JIS system based on JIS X 0208.
|
|
* The Shift JIS values are shifted from the JIS X 0208 values.
|
|
* JIS X 0208 gives details of the shift coded representation.
|
|
* Each two-byte character value is compacted to a 13-bit binary codeword.
|
|
*
|
|
* @type {Object}
|
|
*/
|
|
exports.KANJI = {
|
|
id: 'Kanji',
|
|
bit: 1 << 3,
|
|
ccBits: [8, 10, 12]
|
|
}
|
|
|
|
/**
|
|
* Mixed mode will contain a sequences of data in a combination of any of
|
|
* the modes described above
|
|
*
|
|
* @type {Object}
|
|
*/
|
|
exports.MIXED = {
|
|
bit: -1
|
|
}
|
|
|
|
/**
|
|
* Returns the number of bits needed to store the data length
|
|
* according to QR Code specifications.
|
|
*
|
|
* @param {Mode} mode Data mode
|
|
* @param {Number} version QR Code version
|
|
* @return {Number} Number of bits
|
|
*/
|
|
exports.getCharCountIndicator = function getCharCountIndicator (mode, version) {
|
|
if (!mode.ccBits) throw new Error('Invalid mode: ' + mode)
|
|
|
|
if (!VersionCheck.isValid(version)) {
|
|
throw new Error('Invalid version: ' + version)
|
|
}
|
|
|
|
if (version >= 1 && version < 10) return mode.ccBits[0]
|
|
else if (version < 27) return mode.ccBits[1]
|
|
return mode.ccBits[2]
|
|
}
|
|
|
|
/**
|
|
* Returns the most efficient mode to store the specified data
|
|
*
|
|
* @param {String} dataStr Input data string
|
|
* @return {Mode} Best mode
|
|
*/
|
|
exports.getBestModeForData = function getBestModeForData (dataStr) {
|
|
if (Regex.testNumeric(dataStr)) return exports.NUMERIC
|
|
else if (Regex.testAlphanumeric(dataStr)) return exports.ALPHANUMERIC
|
|
else if (Regex.testKanji(dataStr)) return exports.KANJI
|
|
else return exports.BYTE
|
|
}
|
|
|
|
/**
|
|
* Return mode name as string
|
|
*
|
|
* @param {Mode} mode Mode object
|
|
* @returns {String} Mode name
|
|
*/
|
|
exports.toString = function toString (mode) {
|
|
if (mode && mode.id) return mode.id
|
|
throw new Error('Invalid mode')
|
|
}
|
|
|
|
/**
|
|
* Check if input param is a valid mode object
|
|
*
|
|
* @param {Mode} mode Mode object
|
|
* @returns {Boolean} True if valid mode, false otherwise
|
|
*/
|
|
exports.isValid = function isValid (mode) {
|
|
return mode && mode.bit && mode.ccBits
|
|
}
|
|
|
|
/**
|
|
* Get mode object from its name
|
|
*
|
|
* @param {String} string Mode name
|
|
* @returns {Mode} Mode object
|
|
*/
|
|
function fromString (string) {
|
|
if (typeof string !== 'string') {
|
|
throw new Error('Param is not a string')
|
|
}
|
|
|
|
const lcStr = string.toLowerCase()
|
|
|
|
switch (lcStr) {
|
|
case 'numeric':
|
|
return exports.NUMERIC
|
|
case 'alphanumeric':
|
|
return exports.ALPHANUMERIC
|
|
case 'kanji':
|
|
return exports.KANJI
|
|
case 'byte':
|
|
return exports.BYTE
|
|
default:
|
|
throw new Error('Unknown mode: ' + string)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns mode from a value.
|
|
* If value is not a valid mode, returns defaultValue
|
|
*
|
|
* @param {Mode|String} value Encoding mode
|
|
* @param {Mode} defaultValue Fallback value
|
|
* @return {Mode} Encoding mode
|
|
*/
|
|
exports.from = function from (value, defaultValue) {
|
|
if (exports.isValid(value)) {
|
|
return value
|
|
}
|
|
|
|
try {
|
|
return fromString(value)
|
|
} catch (e) {
|
|
return defaultValue
|
|
}
|
|
}
|