fckeuspy-go/vendor/github.com/liyue201/goqr/decoding.go
2025-09-22 19:42:23 +02:00

717 lines
15 KiB
Go

package goqr
import (
"math"
)
const maxPoly = 64
type galoisField struct {
p int
log []uint8
exp []uint8
}
var gf16Exp = []uint8{
0x01, 0x02, 0x04, 0x08, 0x03, 0x06, 0x0c, 0x0b,
0x05, 0x0a, 0x07, 0x0e, 0x0f, 0x0d, 0x09, 0x01,
}
var gf16Log = []uint8{
0x00, 0x0f, 0x01, 0x04, 0x02, 0x08, 0x05, 0x0a,
0x03, 0x0e, 0x09, 0x07, 0x06, 0x0d, 0x0b, 0x0c,
}
var gf16 = galoisField{
p: 15,
log: gf16Log,
exp: gf16Exp,
}
var gf256Exp = [256]uint8{
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26,
0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9,
0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0,
0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35,
0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,
0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0,
0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1,
0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc,
0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0,
0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f,
0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,
0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88,
0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce,
0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93,
0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc,
0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9,
0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,
0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa,
0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73,
0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e,
0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff,
0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4,
0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,
0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e,
0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6,
0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef,
0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09,
0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5,
0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,
0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83,
0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x01,
}
var gf256Log = [256]uint8{
0x00, 0xff, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6,
0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,
0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81,
0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,
0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21,
0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9,
0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,
0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd,
0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,
0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd,
0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,
0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e,
0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,
0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b,
0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,
0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d,
0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c,
0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,
0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd,
0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,
0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e,
0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76,
0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,
0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa,
0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,
0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51,
0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8,
0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf,
}
var gf256 = galoisField{
255,
gf256Log[:],
gf256Exp[:],
}
/************************************************************************
* Polynomial operations
*/
func polyAdd(dst, src []uint8, c uint8, shift int, gf *galoisField) {
logC := gf.log[c]
if c == 0 {
return
}
for i := 0; i < maxPoly; i++ {
p := i + shift
v := src[i]
if p < 0 || p >= maxPoly {
continue
}
if v == 0 {
continue
}
pos := (int(gf.log[v]) + int(logC)) % gf.p
dst[p] ^= gf.exp[pos]
}
}
func polyEval(s []uint8, x uint8, gf *galoisField) uint8 {
sum := uint8(0)
logX := gf.log[x]
if x == 0 {
return s[0]
}
for i := 0; i < maxPoly; i++ {
c := s[i]
if c == 0 {
continue
}
sum ^= gf.exp[(int(gf.log[c])+int(logX)*i)%gf.p]
}
return sum
}
/************************************************************************
* Berlekamp-Massey algorithm for finding error locator polynomials.
*/
func berlekampMassey(s []uint8, num int, gf *galoisField, sigma []uint8) {
C := make([]uint8, maxPoly)
B := make([]uint8, maxPoly)
L := 0
m := 1
b := uint8(1)
B[0] = 1
C[0] = 1
for n := 0; n < num; n++ {
d := s[n]
for i := 1; i <= L; i++ {
if !(C[i] > 0 && s[n-i] > 0) {
continue
}
d ^= gf.exp[(int(gf.log[C[i]])+int(gf.log[s[n-i]]))%gf.p]
}
mult := gf.exp[(gf.p-int(gf.log[b])+int(gf.log[d]))%gf.p]
if d == 0 {
m++
} else if L*2 <= n {
T := make([]uint8, 0)
T = append(T, C...)
polyAdd(C, B, mult, m, gf)
B = B[:0]
B = append(B, T...)
L = n + 1 - L
b = d
m = 1
} else {
polyAdd(C, B, mult, m, gf)
m++
}
}
sigma = sigma[:0]
sigma = append(sigma, C...)
}
/************************************************************************
* Code stream error correction
*
* Generator polynomial for GF(2^8) is x^8 + x^4 + x^3 + x^2 + 1
*/
func blockSyndromes(data []uint8, bs, npar int, s []uint8) int {
nonzero := 0
for i := 0; i < maxPoly; i++ {
s[i] = 0
}
for i := 0; i < npar; i++ {
for j := 0; j < bs; j++ {
c := data[bs-j-1]
if c == 0 {
continue
}
s[i] ^= gf256Exp[((int)(gf256Log[c])+i*j)%255]
}
if s[i] != 0 {
nonzero = 1
}
}
return nonzero
}
func elocPoly(omega []uint8, s []uint8, sigma []uint8, npar int) {
for i := 0; i < maxPoly; i++ {
omega[i] = 0
}
for i := 0; i < npar; i++ {
a := sigma[i]
logA := gf256Log[a]
if a == 0 {
continue
}
for j := 0; j+1 < maxPoly; j++ {
b := s[j+1]
if i+j >= npar {
break
}
if b == 0 {
continue
}
omega[i+j] ^= gf256Exp[(int(logA)+int(gf256Log[b]))%255]
}
}
}
func correctBlock(data []uint8, ecc *qrRsParams) error {
npar := ecc.bs - ecc.dw
s := make([]uint8, maxPoly)
// Compute syndrome vector
if 0 == blockSyndromes(data, ecc.bs, npar, s) {
return nil
}
sigma := make([]uint8, maxPoly)
berlekampMassey(s, npar, &gf256, sigma)
// Compute derivative of sigma
sigmaDeriv := make([]uint8, maxPoly)
for i := 0; i+1 < maxPoly; i += 2 {
sigmaDeriv[i] = sigma[i+1]
}
// Compute error evaluator polynomial
omega := make([]uint8, maxPoly)
elocPoly(omega, s, sigma, npar-1)
// Find error locations and magnitudes
for i := 0; i < ecc.bs; i++ {
xinv := gf256Exp[255-i]
if 0 == polyEval(sigma, xinv, &gf256) {
sdX := polyEval(sigmaDeriv, xinv, &gf256)
omegaX := polyEval(omega, xinv, &gf256)
error := gf256Exp[(255-int(gf256Log[sdX])+int(gf256Log[omegaX]))%255]
data[ecc.bs-i-1] ^= error
}
}
if blockSyndromes(data, ecc.bs, npar, s) != 0 {
return ErrDataEcc
}
return nil
}
/************************************************************************
* Format value error correction
*
* Generator polynomial for GF(2^4) is x^4 + x + 1
*/
const formatMaxError = 3
const formatSyndrome = formatMaxError * 2
const formatBits = 15
func formatSyndromes(u uint16, s []uint8) int {
nonzero := 0
for i := 0; i < maxPoly; i++ {
s[i] = 0
}
for i := 0; i < formatSyndrome; i++ {
s[i] = 0
for j := 0; j < formatBits; j++ {
if u&(uint16(1 << uint(j))) != 0 {
s[i] ^= gf16Exp[((i+1)*j)%15]
}
}
if s[i] != 0 {
nonzero = 1
}
}
return nonzero
}
func correctFormat(fRet *uint16) error {
u := *fRet
// Evaluate U (received codeword) at each of alpha_1 .. alpha_6
// to get S_1 .. S_6 (but we index them from 0).
s := make([]uint8, maxPoly)
if 0 == formatSyndromes(u, s) {
return nil
}
sigma := make([]uint8, maxPoly)
berlekampMassey(s, formatSyndrome, &gf16, sigma)
// Now, find the roots of the polynomial
for i := 0; i < 15; i++ {
if 0 == polyEval(sigma, gf16Exp[15-i], &gf16) {
u ^= 1 << uint16(i)
}
}
if 0 != formatSyndromes(u, s) {
return ErrFormatEcc
}
*fRet = u
return nil
}
/************************************************************************
* Decoder algorithm
*/
type datastream struct {
raw [qrMaxPayload]uint8
dataBits int
ptr int
data [qrMaxPayload]uint8
}
func maskBit(mask, i, j int) int {
k := 0
switch mask {
case 0:
k = (i + j) % 2
case 1:
k = i % 2
case 2:
k = j % 3
case 3:
k = (i + j) % 3
case 4:
k = ((i / 2) + (j / 3)) % 2
case 5:
k = (i*j)%2 + (i*j)%3
case 6:
k = ((i*j)%2 + (i*j)%3) % 2
case 7:
k = ((i*j)%3 + (i+j)%2) % 2
default:
return 0
}
if k != 0 {
return 0
}
return 1
}
func reservedCell(version, i, j int) int {
ver := &qrVersionDb[version]
size := version*4 + 17
ai := -1
aj := -1
a := 0
// Finder + format: top left
if i < 9 && j < 9 {
return 1
}
// Finder + format: bottom left
if i+8 >= size && j < 9 {
return 1
}
// Finder + format: top right
if i < 9 && j+8 >= size {
return 1
}
// Exclude timing patterns
if i == 6 || j == 6 {
return 1
}
// Exclude Version info, if it exists. Version info sits adjacent to
// the top-right and bottom-left finders in three rows, bounded by
// the timing pattern.
if version >= 7 {
if i < 6 && j+11 >= size {
return 1
}
if i+11 >= size && j < 6 {
return 1
}
}
// Exclude alignment patterns
for a = 0; a < qrMaxAliment && ver.apat[a] != 0; a++ {
p := ver.apat[a]
if int(math.Abs(float64(p-i))) < 3 {
ai = a
}
if int(math.Abs(float64(p-j))) < 3 {
aj = a
}
}
if ai >= 0 && aj >= 0 {
a--
if ai > 0 && ai < a {
return 1
}
if aj > 0 && aj < a {
return 1
}
if aj == a && ai == a {
return 1
}
}
return 0
}
func codestreamEcc(data *QRData, ds *datastream) error {
ver := &qrVersionDb[data.Version]
sbEcc := &ver.ecc[data.EccLevel]
var lbEcc qrRsParams
lbCount := (ver.dataBytes - sbEcc.bs*sbEcc.ns) / (sbEcc.bs + 1)
bc := lbCount + sbEcc.ns
eccOffset := sbEcc.dw*bc + lbCount
dstOffset := 0
lbEcc = *sbEcc
lbEcc.dw++
lbEcc.bs++
for i := 0; i < bc; i++ {
dst := ds.data[dstOffset:]
ecc := sbEcc
if i < sbEcc.ns {
ecc = sbEcc
} else {
ecc = &lbEcc
}
numEc := ecc.bs - ecc.dw
for j := 0; j < ecc.dw; j++ {
dst[j] = ds.raw[j*bc+i]
}
for j := 0; j < numEc; j++ {
dst[ecc.dw+j] = ds.raw[eccOffset+j*bc+i]
}
err := correctBlock(dst, ecc)
if err != nil {
return err
}
dstOffset += ecc.dw
}
ds.dataBits = dstOffset * 8
return nil
}
func bitsRemaining(ds *datastream) int {
return ds.dataBits - ds.ptr
}
func takeBits(ds *datastream, len int) int {
ret := 0
for len > 0 && (ds.ptr < ds.dataBits) {
b := ds.data[ds.ptr>>3]
bitpos := ds.ptr & 7
ret <<= 1
if ((b << uint(bitpos)) & 0x80) != 0 {
ret |= 1
}
ds.ptr++
len--
}
return ret
}
func numericTuple(data *QRData, ds *datastream, bits, digits int) int {
if bitsRemaining(ds) < bits {
return -1
}
tuple := takeBits(ds, bits)
for i := digits - 1; i >= 0; i-- {
data.Payload = append(data.Payload, uint8(tuple%10)+uint8('0'))
tuple /= 10
}
return 0
}
func decodeNumeric(data *QRData, ds *datastream) error {
bits := 14
if data.Version < 10 {
bits = 10
} else if data.Version < 27 {
bits = 12
}
count := takeBits(ds, bits)
if len(data.Payload)+count+1 > qrMaxPayload {
return ErrDataOverflow
}
for count >= 3 {
if numericTuple(data, ds, 10, 3) < 0 {
return ErrDataUnderflow
}
count -= 3
}
if count >= 2 {
if numericTuple(data, ds, 7, 2) < 0 {
return ErrDataUnderflow
}
count -= 2
}
if count > 0 {
if numericTuple(data, ds, 4, 1) < 0 {
return ErrDataUnderflow
}
}
return nil
}
var alphaMap = []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")
func alphaTuple(data *QRData, ds *datastream, bits, digits int) int {
if bitsRemaining(ds) < bits {
return -1
}
tuple := takeBits(ds, bits)
payloadLen := len(data.Payload)
data.Payload = append(data.Payload, make([]uint8, digits)...)
for i := 0; i < digits; i++ {
data.Payload[payloadLen+digits-i-1] = alphaMap[tuple%45]
tuple /= 45
}
return 0
}
func decodeAlpha(data *QRData, ds *datastream) error {
bits := 13
if data.Version < 10 {
bits = 9
} else if data.Version < 27 {
bits = 11
}
count := takeBits(ds, bits)
if len(data.Payload)+count+1 > qrMaxPayload {
return ErrDataOverflow
}
for count >= 2 {
if alphaTuple(data, ds, 11, 2) < 0 {
return ErrDataUnderflow
}
count -= 2
}
if count > 0 {
if alphaTuple(data, ds, 6, 1) < 0 {
return ErrDataUnderflow
}
}
return nil
}
func decodeByte(data *QRData, ds *datastream) error {
bits := 16
if data.Version < 10 {
bits = 8
}
count := takeBits(ds, bits)
if len(data.Payload)+count+1 > qrMaxPayload {
return ErrDataOverflow
}
if bitsRemaining(ds) < count*8 {
return ErrDataUnderflow
}
for i := 0; i < count; i++ {
data.Payload = append(data.Payload, uint8(takeBits(ds, 8)))
}
return nil
}
func decodeKanji(data *QRData, ds *datastream) error {
bits := 12
if data.Version < 10 {
bits = 8
} else if data.Version < 27 {
bits = 10
}
count := takeBits(ds, bits)
if len(data.Payload)+count*2+1 > qrMaxPayload {
return ErrDataOverflow
}
if bitsRemaining(ds) < count*13 {
return ErrDataUnderflow
}
for i := 0; i < count; i++ {
d := takeBits(ds, 13)
msB := d / 0xc0
lsB := d % 0xc0
intermediate := uint16((msB << 8) | lsB)
var sjw uint16
if intermediate+0x8140 <= 0x9ffc {
// bytes are in the range 0x8140 to 0x9FFC
sjw = intermediate + 0x8140
} else {
// bytes are in the range 0xE040 to 0xEBBF
sjw = intermediate + 0xc140
}
data.Payload = append(data.Payload, uint8(sjw>>8))
data.Payload = append(data.Payload, uint8(sjw&0xff))
}
return nil
}
func decodeEci(data *QRData, ds *datastream) error {
if bitsRemaining(ds) < 8 {
return ErrDataOverflow
}
data.Eci = uint32(takeBits(ds, 8))
if (data.Eci & 0xc0) == 0x80 {
if bitsRemaining(ds) < 8 {
return ErrDataUnderflow
}
data.Eci = (data.Eci << 8) | uint32(takeBits(ds, 8))
} else if (data.Eci & 0xe0) == 0xc0 {
if bitsRemaining(ds) < 16 {
return ErrDataUnderflow
}
data.Eci = (data.Eci << 16) | uint32(takeBits(ds, 16))
}
return nil
}
func decodePayload(data *QRData, ds *datastream) error {
for bitsRemaining(ds) >= 4 {
var err error
_type := takeBits(ds, 4)
switch _type {
case qrDataTypeNumeric:
err = decodeNumeric(data, ds)
case qrDataTypeAlpha:
err = decodeAlpha(data, ds)
case qrDataTypeByte:
err = decodeByte(data, ds)
case qrDataTypeKanji:
err = decodeKanji(data, ds)
case 7:
err = decodeEci(data, ds)
default:
goto done
}
if err != nil {
return err
}
if 0 == (_type&(_type-1)) && (_type > data.DataType) {
data.DataType = _type
}
}
done:
return nil
}