import AztecDetectorResult from '../AztecDetectorResult' ; import BitMatrix from '../../common/BitMatrix' ; import DecoderResult from '../../common/DecoderResult' ; import GenericGF from '../../common/reedsolomon/GenericGF' ; import ReedSolomonDecoder from '../../common/reedsolomon/ReedSolomonDecoder' ; import IllegalStateException from '../../IllegalStateException' ; import FormatException from '../../FormatException' ; import StringUtils from '../../common/StringUtils' ; import Integer from '../../util/Integer' ; import { int } from '../../../customTypings' ; enum Table { UPPER , LOWER , MIXED , DIGIT , PUNCT , BINARY } author David Olivier
  export default class Decoder { private static UPPER_TABLE : string [ ] = [ 'CTRL_PS' , ' ' , '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' , 'CTRL_LL' , 'CTRL_ML' , 'CTRL_DL' , 'CTRL_BS' ] ; private static LOWER_TABLE : string [ ] = [ 'CTRL_PS' , ' ' , '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' , 'CTRL_US' , 'CTRL_ML' , 'CTRL_DL' , 'CTRL_BS' ] ; private static MIXED_TABLE : string [ ] = [ 'CTRL_PS' , ' ' , '\\1' , '\\2' , '\\3' , '\\4' , '\\5' , '\\6' , '\\7' , '\b' , '\t' , '\n' , '\\13' , '\f' , '\r' , '\\33' , '\\34' , '\\35' , '\\36' , '\\37' , '@' , '\\' , '^' , '_' , '`' , '|' , '~' , '\\177' , 'CTRL_LL' , 'CTRL_UL' , 'CTRL_PL' , 'CTRL_BS' ] ; private static PUNCT_TABLE : string [ ] = [ '' , '\r' , '\r\n' , '. ' , ', ' , ': ' , '!' , '"' , '#' , '$' , '%' , '&' , '\'' , '(' , ')' , '*' , '+' , ',' , '-' , '.' , '/' , ':' , ';' , '<' , '=' , '>' , '?' , '[' , ']' , '{' , '}' , 'CTRL_UL' ] ; private static DIGIT_TABLE : string [ ] = [ 'CTRL_PS' , ' ' , '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , ',' , '.' , 'CTRL_UL' , 'CTRL_US' ] ; private ddata : AztecDetectorResult ; public decode ( detectorResult ) { this . ddata = detectorResult ; let matrix = detectorResult . getBits ( ) ; let rawbits = this . extractBits ( matrix ) ; let correctedBits = this . correctBits ( rawbits ) ; let rawBytes = Decoder . convertBoolArrayToByteArray ( correctedBits ) ; let result = Decoder . getEncodedData ( correctedBits ) ; let decoderResult = new DecoderResult ( rawBytes , result , null , null ) ; decoderResult . setNumBits ( correctedBits . length ) ; return decoderResult ; } public static highLevelDecode ( correctedBits ) { return this . getEncodedData ( correctedBits ) ; } return private static getEncodedData ( correctedBits ) { let endIndex = correctedBits . length ; let latchTable = Table . UPPER ; let shiftTable = Table . UPPER ; let result = '' ; let index = 0 ; while ( index < endIndex ) { if ( shiftTable === Table . BINARY ) { if ( endIndex - index < 5 ) { break ; } let length = Decoder . readCode ( correctedBits , index , 5 ) ; index += 5 ; if ( length === 0 ) { if ( endIndex - index < 11 ) { break ; } length = Decoder . readCode ( correctedBits , index , 11 ) + 31 ; index += 11 ; } for ( let charCount = 0 ; charCount < length ; charCount ++ ) { if ( endIndex - index < 8 ) { index = endIndex ; break ; } const code = Decoder . readCode ( correctedBits , index , 8 ) ; result += StringUtils . castAsNonUtf8Char ( code ) ; index += 8 ; } shiftTable = latchTable ; } else { let size = shiftTable === Table . DIGIT ? 4 : 5 ; if ( endIndex - index < size ) { break ; } let code = Decoder . readCode ( correctedBits , index , size ) ; index += size ; let str = Decoder . getCharacter ( shiftTable , code ) ; if ( str . startsWith ( 'CTRL_' ) ) { latchTable = shiftTable ; shiftTable = Decoder . getTable ( str . charAt ( 5 ) ) ; if ( str . charAt ( 6 ) === 'L' ) { latchTable = shiftTable ; } } else { result += str ; shiftTable = latchTable ; } } } return result ; } /**
     * gets the table corresponding to the char passed
     */ private static getTable ( t ) { switch ( t ) { case 'L' : return Table . LOWER ; case 'P' : return Table . PUNCT ; case 'M' : return Table . MIXED ; case 'D' : return Table . DIGIT ; case 'B' : return Table . BINARY ; case 'U' : default : return Table . UPPER ; } } param table param code private static getCharacter ( table , code ) { switch ( table ) { case Table . UPPER : return Decoder . UPPER_TABLE [ code ] ; case Table . LOWER : return Decoder . LOWER_TABLE [ code ] ; case Table . MIXED : return Decoder . MIXED_TABLE [ code ] ; case Table . PUNCT : return Decoder . PUNCT_TABLE [ code ] ; case Table . DIGIT : return Decoder . DIGIT_TABLE [ code ] ; default : throw new IllegalStateException ( 'Bad table' ) ; } } return throws private correctBits ( rawbits ) { let gf ; let codewordSize ; if ( this . ddata . getNbLayers ( ) <= 2 ) { codewordSize = 6 ; gf = GenericGF . AZTEC_DATA_6 ; } else if ( this . ddata . getNbLayers ( ) <= 8 ) { codewordSize = 8 ; gf = GenericGF . AZTEC_DATA_8 ; } else if ( this . ddata . getNbLayers ( ) <= 22 ) { codewordSize = 10 ; gf = GenericGF . AZTEC_DATA_10 ; } else { codewordSize = 12 ; gf = GenericGF . AZTEC_DATA_12 ; } let numDataCodewords = this . ddata . getNbDatablocks ( ) ; let numCodewords = rawbits . length / codewordSize ; if ( numCodewords < numDataCodewords ) { throw new FormatException ( ) ; } let offset = rawbits . length % codewordSize ; let dataWords = new Int32Array ( numCodewords ) ; for ( let i = 0 ; i < numCodewords ; i ++ , offset += codewordSize ) { dataWords [ i ] = Decoder . readCode ( rawbits , offset , codewordSize ) ; } try { let rsDecoder = new ReedSolomonDecoder ( gf ) ; rsDecoder . decode ( dataWords , numCodewords - numDataCodewords ) ; } catch ( ex ) { throw new FormatException ( ex ) ; } let mask = ( 1 << codewordSize ) - 1 ; let stuffedBits = 0 ; for ( let i = 0 ; i < numDataCodewords ; i ++ ) { let dataWord = dataWords [ i ] ; if ( dataWord === 0 || dataWord === mask ) { throw new FormatException ( ) ; } else if ( dataWord === 1 || dataWord === mask - 1 ) { stuffedBits ++ ; } } let correctedBits = new Array ( numDataCodewords * codewordSize - stuffedBits ) ; let index = 0 ; for ( let i = 0 ; i < numDataCodewords ; i ++ ) { let dataWord = dataWords [ i ] ; if ( dataWord === 1 || dataWord === mask - 1 ) { correctedBits . fill ( dataWord > 1 , index , index + codewordSize - 1 ) ; index += codewordSize - 1 ; } else { for ( let bit = codewordSize - 1 ; bit >= 0 ; -- bit ) { correctedBits [ index ++ ] = ( dataWord & ( 1 << bit ) ) !== 0 ; } } } return correctedBits ; } return private extractBits ( matrix ) { let compact = this . ddata . isCompact ( ) ; let layers = this . ddata . getNbLayers ( ) ; let baseMatrixSize = ( compact ? 11 : 14 ) + layers * 4 ; let alignmentMap = new Int32Array ( baseMatrixSize ) ; let rawbits = new Array ( this . totalBitsInLayer ( layers , compact ) ) ; if ( compact ) { for ( let i = 0 ; i < alignmentMap . length ; i ++ ) { alignmentMap [ i ] = i ; } } else { let matrixSize = baseMatrixSize + 1 + 2 * Integer . truncDivision ( ( Integer . truncDivision ( baseMatrixSize , 2 ) - 1 ) , 15 ) ; let origCenter = baseMatrixSize / 2 ; let center = Integer . truncDivision ( matrixSize , 2 ) ; for ( let i = 0 ; i < origCenter ; i ++ ) { let newOffset = i + Integer . truncDivision ( i , 15 ) ; alignmentMap [ origCenter - i - 1 ] = center - newOffset - 1 ; alignmentMap [ origCenter + i ] = center + newOffset + 1 ; } } for ( let i = 0 , rowOffset = 0 ; i < layers ; i ++ ) { let rowSize = ( layers - i ) * 4 + ( compact ? 9 : 12 ) ; let low = i * 2 ; let high = baseMatrixSize - 1 - low ; for ( let j = 0 ; j < rowSize ; j ++ ) { let columnOffset = j * 2 ; for ( let k = 0 ; k < 2 ; k ++ ) { rawbits [ rowOffset + columnOffset + k ] = matrix . get ( alignmentMap [ low + k ] , alignmentMap [ low + j ] ) ; rawbits [ rowOffset + 2 * rowSize + columnOffset + k ] = matrix . get ( alignmentMap [ low + j ] , alignmentMap [ high - k ] ) ; rawbits [ rowOffset + 4 * rowSize + columnOffset + k ] = matrix . get ( alignmentMap [ high - k ] , alignmentMap [ high - j ] ) ; rawbits [ rowOffset + 6 * rowSize + columnOffset + k ] = matrix . get ( alignmentMap [ high - j ] , alignmentMap [ low + k ] ) ; } } rowOffset += rowSize * 8 ; } return rawbits ; } /**
     * Reads a code of given length and at given index in an array of bits
     */ private static readCode ( rawbits , startIndex , length ) { let res = 0 ; for ( let i = startIndex ; i < startIndex + length ; i ++ ) { res <<= 1 ; if ( rawbits [ i ] ) { res |= 0x01 ; } } return res ; } /**
     * Reads a code of length 8 in an array of bits, padding with zeros
     */ private static readByte ( rawbits , startIndex ) { let n = rawbits . length - startIndex ; if ( n >= 8 ) { return Decoder . readCode ( rawbits , startIndex , 8 ) ; } return Decoder . readCode ( rawbits , startIndex , n ) << ( 8 - n ) ; } /**
     * Packs a bit array into bytes, most significant bit first
     */ public static convertBoolArrayToByteArray ( boolArr ) { let byteArr = new Uint8Array ( ( boolArr . length + 7 ) / 8 ) ; for ( let i = 0 ; i < byteArr . length ; i ++ ) { byteArr [ i ] = Decoder . readByte ( boolArr , 8 * i ) ; } return byteArr ; } private totalBitsInLayer ( layers , compact ) { return ( ( compact ? 88 : 112 ) + 16 * layers ) * layers ; } }