All files / src/utils create-data.util.js

98.44% Statements 127/129
86.66% Branches 13/15
100% Functions 3/3
98.44% Lines 127/129

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 1301x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x     8x 8x 8x 8x 8x 8x 8x 8x 13x 13x 8x 8x 8x 19x 2x 2x 17x 17x 19x 6x 6x 11x 11x 8x 8x 1x 1x 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 8x 8x 8x 140x 140x 140x 140x 140x 140x 140x 8x 8x 86x 86x 86x 86x 86x 86x 86x 8x 8x 1x 1x 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 140x 140x 8x 8x 8x 8x 8x 8x 8x 8x 86x 86x 86x 8x 8x 8x 1x  
import { QrBitBuffer } from './qr-bit-buffer.js'
import { ECBlocksInfo } from '../error-correction/qr-ec-block.utils.js'
import { getCharCountBitLength } from '../modes/mode-utils.util.js'
import { getErrorCorrectPolynomial } from '../error-correction/ec-polynomial.js'
import { QrPolynomial } from './qr-polynomial.js'
/** @import {ModeObject} from '../modes/mode-bits.constants.js' */
/** @import {ECBlocks} from '../error-correction/qr-ec-block.utils.js' */
 
const PAD0 = 0xEC
const PAD1 = 0x11
 
/**
 *
 * @param {number} typeNumber - qr code version
 * @param {number} errorCorrectionLevel - error correction level
 * @param {Readonly<ModeObject[]>} dataList - qr code raw data
 * @returns {number[]} qr code byte data
 */
export function createData (typeNumber, errorCorrectionLevel, dataList) {
  const blocksInfo = ECBlocksInfo(typeNumber, errorCorrectionLevel)
  const buffer = new QrBitBuffer()
 
  for (const data of dataList) {
    buffer.put(data.mode, 4)
    buffer.put(data.length, getCharCountBitLength(data.mode, typeNumber))
    data.write(buffer)
  }
 
  const totalDataCount = blocksInfo.totalDcCount
 
  if (buffer.bitLength > totalDataCount * 8) {
    throw Error(`code length overflow. (${buffer.bitLength} > ${totalDataCount * 8})`)
  }
 
  // end code
  if (buffer.bitLength + 4 <= totalDataCount * 8) {
    buffer.put(0, 4)
  }
 
  // padding
  while (buffer.bitLength % 8 !== 0) {
    buffer.putBit(0)
  }
 
  // padding
  while (true) {
    if (buffer.bitLength >= totalDataCount * 8) {
      break
    }
    buffer.put(PAD0, 8)
 
    if (buffer.bitLength >= totalDataCount * 8) {
      break
    }
    buffer.put(PAD1, 8)
  }
 
  return createBytes(buffer, blocksInfo)
};
 
/**
 * @param {QrBitBuffer} buffer - data buffer
 * @param {ECBlocksInfo} blocksInfo - error correction blocks info
 */
function createBytes (buffer, blocksInfo) {
  const { maxDcCount, maxEcCount, blocks: ecBlocks, totalCount: totalCodeCount } = blocksInfo
  const { ecdata, dcdata } = createCodewordsData(buffer, ecBlocks)
 
  /** @type {number[]} */
  const data = new Array(totalCodeCount)
  let index = 0
 
  for (let i = 0; i < maxDcCount; i += 1) {
    for (let r = 0; r < ecBlocks.length; r += 1) {
      if (i < dcdata[r].length) {
        data[index] = dcdata[r][i]
        index += 1
      }
    }
  }
 
  for (let i = 0; i < maxEcCount; i += 1) {
    for (let r = 0; r < ecBlocks.length; r += 1) {
      if (i < ecdata[r].length) {
        data[index] = ecdata[r][i]
        index += 1
      }
    }
  }
 
  return data
};
 
/**
 * @param {QrBitBuffer} buffer - - data buffer
 * @param {ECBlocks} ecBlocks - error correction blocks
 */
function createCodewordsData (buffer, ecBlocks) {
  let offset = 0
 
  /** @type {number[][]} */
  const dcdata = new Array(ecBlocks.length)
  /** @type {number[][]} */
  const ecdata = new Array(ecBlocks.length)
 
  for (let r = 0; r < ecBlocks.length; r += 1) {
    const dcCount = ecBlocks[r].dataCount
    const ecCount = ecBlocks[r].ecCount
 
    dcdata[r] = new Array(dcCount)
 
    for (let i = 0, e = dcdata[r].length; i < e; i += 1) {
      dcdata[r][i] = 0xff & buffer.byteBuffer[i + offset]
    }
    offset += dcCount
 
    const rsPoly = getErrorCorrectPolynomial(ecCount)
    const rawPoly = QrPolynomial(dcdata[r], rsPoly.length - 1)
 
    const modPoly = rawPoly.mod(rsPoly)
    ecdata[r] = new Array(rsPoly.length - 1)
    for (let i = 0; i < ecdata[r].length; i += 1) {
      const modIndex = i + modPoly.length - ecdata[r].length
      ecdata[r][i] = (modIndex >= 0) ? modPoly.getAt(modIndex) : 0
    }
  }
 
  return { ecdata, dcdata }
};