All files / src/modes kanji.mode.js

91.66% Statements 66/72
80% Branches 12/15
100% Functions 3/3
91.66% Lines 66/72

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 731x 1x 1x 1x 1x 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 8x 8x 8x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 14x 14x 14x 14x 14x         14x 14x 14x 14x 14x 2x 2x     2x 1x 1x 1x 1x 1x 1x 8x 8x 8x 5x 5x 3x 3x 8x 15x 15x 15x 1x 15x 1x 1x 14x 14x 2x 2x  
import { MODE_KANJI } from './mode-bits.constants.js'
import { textToSjisBytes } from '../utils/text-decode-encode.util.js'
 
/**
 * Create QR code Kanji mode object
 * @param {string} data - data of mode object
 * @returns {import('./mode-bits.constants.js').ModeObject & {readonly bytes: Uint8Array}} created mode object
 */
export const QrKanji = (data) => {
  const bytes = textToSjisBytes(data)
  return Object.freeze({
    data,
    bytes,
    mode: MODE_KANJI,
    length: ~~(bytes.length / 2),
    write: writeDataToBitBuffer.bind(null, bytes),
  })
}
 
/**
 * Writes kanji data to bit buffer that will be used to generate the QR code
 * @param {Uint8Array} bytes - QrKanji mode object data byte array
 * @param {import("./../utils/qr-bit-buffer.js").QrBitBuffer} buffer - target bit buffer
 */
function writeDataToBitBuffer (bytes, buffer) {
  let i = 0
 
  while (i + 1 < bytes.length) {
    let c = ((0xff & bytes[i]) << 8) | (0xff & bytes[i + 1])
 
    if (c >= 0x8140 && c <= 0x9FFC) {
      c -= 0x8140
    } else if (c >= 0xE040 && c <= 0xEBBF) {
      c -= 0xC140
    } else {
      throw Error(`illegal char at ${i + 1}/${c}`)
    }
 
    c = ((c >>> 8) & 0xff) * 0xC0 + (c & 0xff)
    buffer.put(c, 13)
    i += 2
  }
 
  if (i < bytes.length) {
    throw Error(`illegal char at ${i + 1}`)
  }
}
 
/**
 * @param {string} text - text to validate
 * @returns {import('./mode-bits.constants.js').ModeObject & {readonly bytes: Uint8Array} | null} created mode object or null if invalid
 */
export function getValidQrKanjiOrNull (text) {
  const modeObject = QrKanji(text)
  const { bytes } = modeObject
  if (bytes.length % 2 === 1) {
    return null
  }
  let i = 0
 
  while (i + 1 < bytes.length) {
    const c = ((0xff & bytes[i]) << 8) | (0xff & bytes[i + 1])
    if (!(
      (c >= 0x8140 && c <= 0x9FFC) ||
      (c >= 0xE040 && c <= 0xEBBF)
    )) {
      return null
    }
    i += 2
  }
  return modeObject
}