/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import {qrcode} from './qrcode'; export default function QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode) { this.blockPointer = 0; this.bitPointer = 7; this.dataLength = 0; this.blocks = blocks; this.numErrorCorrectionCode = numErrorCorrectionCode; if (version <= 9) this.dataLengthMode = 0; else if (version >= 10 && version <= 26) this.dataLengthMode = 1; else if (version >= 27 && version <= 40) this.dataLengthMode = 2; } QRCodeDataBlockReader.prototype.getNextBits = function(numBits) { var bits = 0; if (numBits < this.bitPointer + 1) { // next word fits into current data block var mask = 0; for (var i = 0; i < numBits; i++) { mask += (1 << i); } mask <<= (this.bitPointer - numBits + 1); bits = (this.blocks[this.blockPointer] & mask) >> (this.bitPointer - numBits + 1); this.bitPointer -= numBits; return bits; } else if (numBits < this.bitPointer + 1 + 8) { // next word crosses 2 data blocks var mask1 = 0; for (var i = 0; i < this.bitPointer + 1; i++) { mask1 += (1 << i); } bits = (this.blocks[this.blockPointer] & mask1) << (numBits - (this.bitPointer + 1)); this.blockPointer++; bits += ((this.blocks[this.blockPointer]) >> (8 - (numBits - (this.bitPointer + 1)))); this.bitPointer = this.bitPointer - numBits % 8; if (this.bitPointer < 0) { this.bitPointer = 8 + this.bitPointer; } return bits; } else if (numBits < this.bitPointer + 1 + 16) { // next word crosses 3 data blocks var mask1 = 0; // mask of first block var mask3 = 0; // mask of 3rd block //bitPointer + 1 : number of bits of the 1st block //8 : number of the 2nd block (note that use already 8bits because next word uses 3 data blocks) //numBits - (bitPointer + 1 + 8) : number of bits of the 3rd block for (var i = 0; i < this.bitPointer + 1; i++) { mask1 += (1 << i); } var bitsFirstBlock = (this.blocks[this.blockPointer] & mask1) << (numBits - (this.bitPointer + 1)); this.blockPointer++; var bitsSecondBlock = this.blocks[this.blockPointer] << (numBits - (this.bitPointer + 1 + 8)); this.blockPointer++; for (var i = 0; i < numBits - (this.bitPointer + 1 + 8); i++) { mask3 += (1 << i); } mask3 <<= 8 - (numBits - (this.bitPointer + 1 + 8)); var bitsThirdBlock = (this.blocks[this.blockPointer] & mask3) >> (8 - (numBits - (this.bitPointer + 1 + 8))); bits = bitsFirstBlock + bitsSecondBlock + bitsThirdBlock; this.bitPointer = this.bitPointer - (numBits - 8) % 8; if (this.bitPointer < 0) { this.bitPointer = 8 + this.bitPointer; } return bits; } else { return 0; } }; QRCodeDataBlockReader.prototype.NextMode = function() { if ((this.blockPointer > this.blocks.length - this.numErrorCorrectionCode - 2)) return 0; else return this.getNextBits(4); }; QRCodeDataBlockReader.prototype.getDataLength = function(modeIndicator) { var index = 0; while (true) { if ((modeIndicator >> index) == 1) break; index++; } return this.getNextBits(qrcode.sizeOfDataLengthInfo[this.dataLengthMode][index]); }; QRCodeDataBlockReader.prototype.getRomanAndFigureString = function(dataLength) { var length = dataLength; var intData = 0; var strData = ""; var tableRomanAndFigure = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':']; do { if (length > 1) { intData = this.getNextBits(11); var firstLetter = Math.floor(intData / 45); var secondLetter = intData % 45; strData += tableRomanAndFigure[firstLetter]; strData += tableRomanAndFigure[secondLetter]; length -= 2; } else if (length == 1) { intData = this.getNextBits(6); strData += tableRomanAndFigure[intData]; length -= 1; } } while (length > 0); return strData; }; QRCodeDataBlockReader.prototype.getFigureString = function(dataLength) { var length = dataLength; var intData = 0; var strData = ""; do { if (length >= 3) { intData = this.getNextBits(10); if (intData < 100) strData += "0"; if (intData < 10) strData += "0"; length -= 3; } else if (length == 2) { intData = this.getNextBits(7); if (intData < 10) strData += "0"; length -= 2; } else if (length == 1) { intData = this.getNextBits(4); length -= 1; } strData += intData; } while (length > 0); return strData; }; QRCodeDataBlockReader.prototype.get8bitByteArray = function(dataLength) { var length = dataLength; var intData = 0; var output = []; do { intData = this.getNextBits(8); output.push(intData); length--; } while (length > 0); return output; }; QRCodeDataBlockReader.prototype.getKanjiString = function(dataLength) { var length = dataLength; var intData = 0; var unicodeString = ""; do { intData = this.getNextBits(13); var lowerByte = intData % 0xC0; var higherByte = intData / 0xC0; var tempWord = (higherByte << 8) + lowerByte; var shiftjisWord = 0; if (tempWord + 0x8140 <= 0x9FFC) { // between 8140 - 9FFC on Shift_JIS character set shiftjisWord = tempWord + 0x8140; } else { // between E040 - EBBF on Shift_JIS character set shiftjisWord = tempWord + 0xC140; } unicodeString += String.fromCharCode(shiftjisWord); length--; } while (length > 0); return unicodeString; }; Object.defineProperty(QRCodeDataBlockReader.prototype, "DataByte", { get: function() { var output = []; var MODE_NUMBER = 1; var MODE_ROMAN_AND_NUMBER = 2; var MODE_8BIT_BYTE = 4; var MODE_KANJI = 8; do { var mode = this.NextMode(); if (mode == 0) { if (output.length > 0) break; else throw "Empty data block"; } //if (mode != 1 && mode != 2 && mode != 4 && mode != 8) //} if (mode != MODE_NUMBER && mode != MODE_ROMAN_AND_NUMBER && mode != MODE_8BIT_BYTE && mode != MODE_KANJI && mode != 7) { /* canvas.println("Invalid mode: " + mode); mode = guessMode(mode); canvas.println("Guessed mode: " + mode); */ throw "Invalid mode: " + mode + " in (block:" + this.blockPointer + " bit:" + this.bitPointer + ")"; } var dataLength = this.getDataLength(mode); if (dataLength < 1) throw "Invalid data length: " + dataLength; switch (mode) { case MODE_NUMBER: var temp_str = this.getFigureString(dataLength); var ta = new Array(temp_str.length); for (var j = 0; j < temp_str.length; j++) ta[j] = temp_str.charCodeAt(j); output.push(ta); break; case MODE_ROMAN_AND_NUMBER: var temp_str = this.getRomanAndFigureString(dataLength); var ta = new Array(temp_str.length); for (var j = 0; j < temp_str.length; j++) ta[j] = temp_str.charCodeAt(j); output.push(ta); break; case MODE_8BIT_BYTE: var temp_sbyteArray3 = this.get8bitByteArray(dataLength); output.push(temp_sbyteArray3); break; case MODE_KANJI: var temp_str = this.getKanjiString(dataLength); output.push(temp_str); break; } // } while (true); return output; } });