Advance KDE Plasma and Qt integration
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,953 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <iconv.h>
|
||||
#if HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
#include "../qrspec.h"
|
||||
#include "../bitstream.h"
|
||||
#include "../mask.h"
|
||||
#include "../mqrspec.h"
|
||||
#include "../mmask.h"
|
||||
#include "common.h"
|
||||
#include "decoder.h"
|
||||
|
||||
static unsigned int bitToInt(unsigned char *bits, int length)
|
||||
{
|
||||
int i;
|
||||
unsigned int val = 0;
|
||||
|
||||
for(i=0; i<length; i++) {
|
||||
val = val << 1;
|
||||
val |= (bits[i] & 1);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int decodeLength(int *bits_length, unsigned char **bits, QRencodeMode mode, int version, int mqr)
|
||||
{
|
||||
int i;
|
||||
int length = 0;
|
||||
int lbits;
|
||||
|
||||
if(mqr) {
|
||||
lbits = MQRspec_lengthIndicator(mode, version);
|
||||
} else {
|
||||
lbits = QRspec_lengthIndicator(mode, version);
|
||||
}
|
||||
|
||||
if(*bits_length < lbits) {
|
||||
printf("Bit length is too short: %d\n", *bits_length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = 0;
|
||||
for(i=0; i<lbits; i++) {
|
||||
length = length << 1;
|
||||
length += (*bits)[i];
|
||||
}
|
||||
|
||||
*bits_length -= lbits;
|
||||
*bits += lbits;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static DataChunk *decodeNum(int *bits_length, unsigned char **bits, int version, int mqr)
|
||||
{
|
||||
int i;
|
||||
int size, sizeInBit, words, remain;
|
||||
unsigned char *p;
|
||||
char *buf, *q;
|
||||
unsigned int val;
|
||||
DataChunk *chunk;
|
||||
|
||||
size = decodeLength(bits_length, bits, QR_MODE_NUM, version, mqr);
|
||||
if(size < 0) return NULL;
|
||||
|
||||
words = size / 3;
|
||||
remain = size - words * 3;
|
||||
sizeInBit = words * 10;
|
||||
if(remain == 2) {
|
||||
sizeInBit += 7;
|
||||
} else if(remain == 1) {
|
||||
sizeInBit += 4;
|
||||
}
|
||||
if(*bits_length < sizeInBit) {
|
||||
printf("Bit length is too short: %d, expected %d.\n", *bits_length, sizeInBit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = (char *)malloc((size_t)size + 1);
|
||||
p = *bits;
|
||||
q = buf;
|
||||
for(i=0; i<words; i++) {
|
||||
val = bitToInt(p, 10);
|
||||
sprintf(q, "%03d", val);
|
||||
p += 10;
|
||||
q += 3;
|
||||
}
|
||||
if(remain == 2) {
|
||||
val = bitToInt(p, 7);
|
||||
sprintf(q, "%02d", val);
|
||||
} else if(remain == 1) {
|
||||
val = bitToInt(p, 4);
|
||||
sprintf(q, "%1d", val);
|
||||
}
|
||||
buf[size] = '\0';
|
||||
|
||||
chunk = DataChunk_new(QR_MODE_NUM);
|
||||
chunk->size = size;
|
||||
chunk->data = (unsigned char *)buf;
|
||||
*bits_length -= sizeInBit;
|
||||
*bits += sizeInBit;
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
static const char decodeAnTable[45] = {
|
||||
'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', ' ', '$', '%', '*',
|
||||
'+', '-', '.', '/', ':'
|
||||
};
|
||||
|
||||
static DataChunk *decodeAn(int *bits_length, unsigned char **bits, int version, int mqr)
|
||||
{
|
||||
int i;
|
||||
int size, sizeInBit, words, remain;
|
||||
unsigned char *p;
|
||||
char *buf, *q;
|
||||
unsigned int val;
|
||||
int ch, cl;
|
||||
DataChunk *chunk;
|
||||
|
||||
size = decodeLength(bits_length, bits, QR_MODE_AN, version, mqr);
|
||||
if(size < 0) return NULL;
|
||||
|
||||
words = size / 2;
|
||||
remain = size - words * 2;
|
||||
sizeInBit = words * 11 + remain * 6;
|
||||
if(*bits_length < sizeInBit) {
|
||||
printf("Bit length is too short: %d, expected %d.\n", *bits_length, sizeInBit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = (char *)malloc((size_t)size + 1);
|
||||
p = *bits;
|
||||
q = buf;
|
||||
for(i=0; i<words; i++) {
|
||||
val = bitToInt(p, 11);
|
||||
ch = (int)(val / 45);
|
||||
cl = (int)(val % 45);
|
||||
sprintf(q, "%c%c", decodeAnTable[ch], decodeAnTable[cl]);
|
||||
p += 11;
|
||||
q += 2;
|
||||
}
|
||||
if(remain == 1) {
|
||||
val = bitToInt(p, 6);
|
||||
sprintf(q, "%c", decodeAnTable[val]);
|
||||
}
|
||||
|
||||
chunk = DataChunk_new(QR_MODE_AN);
|
||||
chunk->size = size;
|
||||
chunk->data = (unsigned char *)buf;
|
||||
*bits_length -= sizeInBit;
|
||||
*bits += sizeInBit;
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
static DataChunk *decode8(int *bits_length, unsigned char **bits, int version, int mqr)
|
||||
{
|
||||
int i;
|
||||
int size, sizeInBit;
|
||||
unsigned char *p;
|
||||
unsigned char *buf, *q;
|
||||
DataChunk *chunk;
|
||||
|
||||
size = decodeLength(bits_length, bits, QR_MODE_8, version, mqr);
|
||||
if(size < 0) return NULL;
|
||||
|
||||
sizeInBit = size * 8;
|
||||
if(*bits_length < sizeInBit) {
|
||||
printf("Bit length is too short: %d, expected %d.\n", *bits_length, sizeInBit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = (unsigned char *)malloc((size_t)size);
|
||||
p = *bits;
|
||||
q = buf;
|
||||
for(i=0; i<size; i++) {
|
||||
*q = (unsigned char)bitToInt(p, 8);
|
||||
p += 8;
|
||||
q += 1;
|
||||
}
|
||||
|
||||
chunk = DataChunk_new(QR_MODE_8);
|
||||
chunk->size = size;
|
||||
chunk->data = buf;
|
||||
*bits_length -= sizeInBit;
|
||||
*bits += sizeInBit;
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
static DataChunk *decodeKanji(int *bits_length, unsigned char **bits, int version, int mqr)
|
||||
{
|
||||
int i;
|
||||
int size, sizeInBit;
|
||||
unsigned char *p;
|
||||
char *buf, *q;
|
||||
unsigned int val;
|
||||
unsigned int ch, cl;
|
||||
DataChunk *chunk;
|
||||
|
||||
size = decodeLength(bits_length, bits, QR_MODE_KANJI, version, mqr);
|
||||
if(size < 0) return NULL;
|
||||
|
||||
sizeInBit = size * 13;
|
||||
if(*bits_length < sizeInBit) {
|
||||
printf("Bit length is too short: %d, expected %d.\n", *bits_length, sizeInBit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = (char *)malloc((size_t)size * 2 + 1);
|
||||
p = *bits;
|
||||
q = buf;
|
||||
for(i=0; i<size; i++) {
|
||||
val = bitToInt(p, 13);
|
||||
ch = val / 0xc0;
|
||||
cl = val - ch * 0xc0;
|
||||
val = ch * 256 + cl;
|
||||
if(val >= 0x1f00) {
|
||||
val += 0xc140;
|
||||
} else {
|
||||
val += 0x8140;
|
||||
}
|
||||
sprintf(q, "%c%c", (val>>8) & 0xff, val & 0xff);
|
||||
p += 13;
|
||||
q += 2;
|
||||
}
|
||||
|
||||
chunk = DataChunk_new(QR_MODE_KANJI);
|
||||
chunk->size = size * 2;
|
||||
chunk->data = (unsigned char *)buf;
|
||||
*bits_length -= sizeInBit;
|
||||
*bits += sizeInBit;
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
static DataChunk *decodeChunk(int *bits_length, unsigned char **bits, int version)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if(*bits_length < 4) {
|
||||
return NULL;
|
||||
}
|
||||
val = bitToInt(*bits, 4);
|
||||
*bits_length -= 4;
|
||||
*bits += 4;
|
||||
switch(val) {
|
||||
case 0:
|
||||
return NULL;
|
||||
case 1:
|
||||
return decodeNum(bits_length, bits, version, 0);
|
||||
case 2:
|
||||
return decodeAn(bits_length, bits, version, 0);
|
||||
case 4:
|
||||
return decode8(bits_length, bits, version, 0);
|
||||
case 8:
|
||||
return decodeKanji(bits_length, bits, version, 0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Invalid mode in a chunk: %d\n", val);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DataChunk *decodeChunkMQR(int *bits_length, unsigned char **bits, int version)
|
||||
{
|
||||
int modebits, termbits;
|
||||
unsigned int val;
|
||||
|
||||
modebits = version - 1;
|
||||
termbits = version * 2 + 1;
|
||||
if(*bits_length >= termbits) {
|
||||
val = bitToInt(*bits, termbits);
|
||||
if(val == 0) {
|
||||
*bits += termbits;
|
||||
*bits_length -= termbits;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if(*bits_length < modebits) {
|
||||
val = bitToInt(*bits, *bits_length);
|
||||
} else {
|
||||
val = bitToInt(*bits, modebits);
|
||||
}
|
||||
if(val == 0) {
|
||||
return NULL;
|
||||
} else {
|
||||
printf("Terminating bits include 1-bit.\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
val = bitToInt(*bits, modebits);
|
||||
if(version == 4 && val > 3) {
|
||||
printf("Invalid mode number %d.\n", val);
|
||||
}
|
||||
*bits_length -= modebits;
|
||||
*bits += modebits;
|
||||
switch(val) {
|
||||
case 0:
|
||||
return decodeNum(bits_length, bits, version, 1);
|
||||
case 1:
|
||||
return decodeAn(bits_length, bits, version, 1);
|
||||
case 2:
|
||||
return decode8(bits_length, bits, version, 1);
|
||||
case 3:
|
||||
return decodeKanji(bits_length, bits, version, 1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Invalid mode in a chunk: %d\n", val);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int appendChunk(QRdata *qrdata, int *bits_length, unsigned char **bits)
|
||||
{
|
||||
DataChunk *chunk;
|
||||
|
||||
if(qrdata->mqr) {
|
||||
chunk = decodeChunkMQR(bits_length, bits, qrdata->version);
|
||||
} else {
|
||||
chunk = decodeChunk(bits_length, bits, qrdata->version);
|
||||
}
|
||||
if(chunk == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(qrdata->last == NULL) {
|
||||
qrdata->chunks = chunk;
|
||||
} else {
|
||||
qrdata->last->next = chunk;
|
||||
}
|
||||
qrdata->last = chunk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QRdata *QRdata_new(void)
|
||||
{
|
||||
QRdata *qrdata;
|
||||
|
||||
qrdata = (QRdata *)calloc(sizeof(QRdata), 1);
|
||||
if(qrdata == NULL) return NULL;
|
||||
|
||||
qrdata->eccResult = 0;
|
||||
|
||||
return qrdata;
|
||||
}
|
||||
|
||||
QRdata *QRdata_newMQR(void)
|
||||
{
|
||||
QRdata *qrdata;
|
||||
|
||||
qrdata = QRdata_new();
|
||||
if(qrdata == NULL) return NULL;
|
||||
|
||||
qrdata->mqr = 1;
|
||||
|
||||
return qrdata;
|
||||
}
|
||||
|
||||
void QRdata_free(QRdata *qrdata)
|
||||
{
|
||||
DataChunk_freeList(qrdata->chunks);
|
||||
if(qrdata->data != NULL) {
|
||||
free(qrdata->data);
|
||||
}
|
||||
free(qrdata);
|
||||
}
|
||||
|
||||
static int QRdata_decodeBits(QRdata *qrdata, int length, unsigned char *bits)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
while(ret == 0) {
|
||||
ret = appendChunk(qrdata, &length, &bits);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int QRdata_decodeBitStream(QRdata *qrdata, BitStream *bstream)
|
||||
{
|
||||
return QRdata_decodeBits(qrdata, bstream->length, bstream->data);
|
||||
}
|
||||
|
||||
void QRdata_dump(QRdata *data)
|
||||
{
|
||||
DataChunk_dumpChunkList(data->chunks);
|
||||
}
|
||||
|
||||
int QRcode_decodeVersion(QRcode *code)
|
||||
{
|
||||
unsigned int v1, v2;
|
||||
int x, y, width;
|
||||
unsigned char *p;
|
||||
|
||||
width = code->width;
|
||||
if(width < 45) {
|
||||
return (width - 21)/ 4 + 1;
|
||||
}
|
||||
|
||||
v1 = 0;
|
||||
p = code->data + width * (width - 9) + 5;
|
||||
for(x=0; x<6; x++) {
|
||||
for(y=0; y<3; y++) {
|
||||
v1 = v1 << 1;
|
||||
v1 |= *(p - y * width - x) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
v2 = 0;
|
||||
p = code->data + width * 5 + width - 9;
|
||||
for(y=0; y<6; y++) {
|
||||
for(x=0; x<3; x++) {
|
||||
v2 = v2 << 1;
|
||||
v2 |= *(p - y * width - x) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(v1 != v2) {
|
||||
printf("Two verion patterns are different.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)(v1 >> 12);
|
||||
}
|
||||
|
||||
int QRcode_decodeFormat(QRcode *code, QRecLevel *level, int *mask)
|
||||
{
|
||||
unsigned int v1, v2;
|
||||
int i, width;
|
||||
unsigned char *p;
|
||||
|
||||
width = code->width;
|
||||
|
||||
v1 = 0;
|
||||
p = code->data + width * 8;
|
||||
for(i=0; i<8; i++) {
|
||||
v1 = v1 << 1;
|
||||
if(i < 6) {
|
||||
v1 |= *(p + i) & 1;
|
||||
} else {
|
||||
v1 |= *(p + i + 1) & 1;
|
||||
}
|
||||
}
|
||||
p = code->data + width * 7 + 8;
|
||||
for(i=0; i<7; i++) {
|
||||
v1 = v1 << 1;
|
||||
if(i < 1) {
|
||||
v1 |= *(p - width * i) & 1;
|
||||
} else {
|
||||
v1 |= *(p - width * (i + 1)) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
v2 = 0;
|
||||
p = code->data + width * (width - 1) + 8;
|
||||
for(i=0; i<7; i++) {
|
||||
v2 = v2 << 1;
|
||||
v2 |= *(p - width * i) & 1;
|
||||
}
|
||||
p = code->data + width * 8 + width - 8;
|
||||
for(i=0; i<8; i++) {
|
||||
v2 = v2 << 1;
|
||||
v2 |= *(p + i) & 1;
|
||||
}
|
||||
|
||||
if(v1 != v2) {
|
||||
printf("Two format infos are different.\n");
|
||||
return -1;
|
||||
}
|
||||
v1 = (v1 ^ 0x5412) >> 10;
|
||||
*mask = v1 & 7;
|
||||
switch((v1 >> 3) & 3) {
|
||||
case 1:
|
||||
*level = QR_ECLEVEL_L;
|
||||
break;
|
||||
case 0:
|
||||
*level = QR_ECLEVEL_M;
|
||||
break;
|
||||
case 3:
|
||||
*level = QR_ECLEVEL_Q;
|
||||
break;
|
||||
case 2:
|
||||
*level = QR_ECLEVEL_H;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *unmask(QRcode *code, QRecLevel level, int mask)
|
||||
{
|
||||
unsigned char *unmasked;
|
||||
|
||||
unmasked = Mask_makeMask(code->width, code->data, mask, level);
|
||||
|
||||
return unmasked;
|
||||
}
|
||||
|
||||
unsigned char *QRcode_unmask(QRcode *code)
|
||||
{
|
||||
int ret, version, mask;
|
||||
QRecLevel level;
|
||||
|
||||
version = QRcode_decodeVersion(code);
|
||||
if(version < 1) return NULL;
|
||||
ret = QRcode_decodeFormat(code, &level, &mask);
|
||||
if(ret < 0) return NULL;
|
||||
|
||||
return unmask(code, level, mask);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
unsigned char *frame;
|
||||
int x, y;
|
||||
int dir;
|
||||
int bit;
|
||||
int mqr;
|
||||
} FrameFiller;
|
||||
|
||||
static FrameFiller *FrameFiller_new(int width, unsigned char *frame, int mqr)
|
||||
{
|
||||
FrameFiller *filler;
|
||||
|
||||
filler = (FrameFiller *)malloc(sizeof(FrameFiller));
|
||||
if(filler == NULL) return NULL;
|
||||
filler->width = width;
|
||||
filler->frame = frame;
|
||||
filler->x = width - 1;
|
||||
filler->y = width - 1;
|
||||
filler->dir = -1;
|
||||
filler->bit = -1;
|
||||
filler->mqr = mqr;
|
||||
|
||||
return filler;
|
||||
}
|
||||
|
||||
static unsigned char *FrameFiller_next(FrameFiller *filler)
|
||||
{
|
||||
unsigned char *p;
|
||||
int x, y, w;
|
||||
|
||||
if(filler->bit == -1) {
|
||||
filler->bit = 0;
|
||||
return filler->frame + filler->y * filler->width + filler->x;
|
||||
}
|
||||
|
||||
x = filler->x;
|
||||
y = filler->y;
|
||||
p = filler->frame;
|
||||
w = filler->width;
|
||||
|
||||
if(filler->bit == 0) {
|
||||
x--;
|
||||
filler->bit++;
|
||||
} else {
|
||||
x++;
|
||||
y += filler->dir;
|
||||
filler->bit--;
|
||||
}
|
||||
|
||||
if(filler->dir < 0) {
|
||||
if(y < 0) {
|
||||
y = 0;
|
||||
x -= 2;
|
||||
filler->dir = 1;
|
||||
if(!filler->mqr && x == 6) {
|
||||
x--;
|
||||
y = 9;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(y == w) {
|
||||
y = w - 1;
|
||||
x -= 2;
|
||||
filler->dir = -1;
|
||||
if(!filler->mqr && x == 6) {
|
||||
x--;
|
||||
y -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(x < 0 || y < 0) return NULL;
|
||||
|
||||
filler->x = x;
|
||||
filler->y = y;
|
||||
|
||||
if(p[y * w + x] & 0x80) {
|
||||
// This tail recursion could be optimized.
|
||||
return FrameFiller_next(filler);
|
||||
}
|
||||
return &p[y * w + x];
|
||||
}
|
||||
|
||||
static BitStream *extractBits(int width, unsigned char *frame, int spec[5])
|
||||
{
|
||||
BitStream *bstream;
|
||||
unsigned char *bits, *p, *q;
|
||||
FrameFiller *filler;
|
||||
int i, j;
|
||||
int col, row, d1, b1, blocks, idx, words;
|
||||
|
||||
blocks = QRspec_rsBlockNum(spec);
|
||||
words = QRspec_rsDataLength(spec);
|
||||
d1 = QRspec_rsDataCodes1(spec);
|
||||
b1 = QRspec_rsBlockNum1(spec);
|
||||
bits = (unsigned char *)malloc((size_t)words * 8);
|
||||
/*
|
||||
* 00 01 02 03 04 05 06 07 08 09
|
||||
* 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
|
||||
*/
|
||||
|
||||
row = col = 0;
|
||||
filler = FrameFiller_new(width, frame, 0);
|
||||
for(i=0; i<words; i++) {
|
||||
col = i / blocks;
|
||||
row = i % blocks + ((col >= d1)?b1:0);
|
||||
idx = d1 * row + col + ((row > b1)?(row-b1):0);
|
||||
q = bits + idx * 8;
|
||||
for(j=0; j<8; j++) {
|
||||
p = FrameFiller_next(filler);
|
||||
q[j] = *p & 1;
|
||||
}
|
||||
}
|
||||
free(filler);
|
||||
|
||||
bstream = BitStream_newWithBits((size_t)words * 8, bits);
|
||||
free(bits);
|
||||
|
||||
return bstream;
|
||||
}
|
||||
|
||||
BitStream *QRcode_extractBits(QRcode *code, int *dataLength, int *eccLength)
|
||||
{
|
||||
BitStream *bstream;
|
||||
unsigned char *unmasked;
|
||||
int spec[5];
|
||||
int ret, version, mask;
|
||||
QRecLevel level;
|
||||
|
||||
version = QRcode_decodeVersion(code);
|
||||
if(version < 1) return NULL;
|
||||
ret = QRcode_decodeFormat(code, &level, &mask);
|
||||
if(ret < 0) return NULL;
|
||||
|
||||
QRspec_getEccSpec(version, level, spec);
|
||||
|
||||
unmasked = unmask(code, level, mask);
|
||||
if(unmasked == NULL) return NULL;
|
||||
|
||||
bstream = extractBits(code->width, unmasked, spec);
|
||||
free(unmasked);
|
||||
|
||||
*dataLength = QRspec_rsDataLength(spec) * 8;
|
||||
*eccLength = QRspec_rsEccLength(spec) * 8;
|
||||
|
||||
return bstream;
|
||||
}
|
||||
|
||||
static int checkRemainderWords(int length, unsigned char *bits, int remainder)
|
||||
{
|
||||
int rbits, words;
|
||||
unsigned char *p, v;
|
||||
int i;
|
||||
|
||||
words = remainder / 8;
|
||||
rbits = remainder - words * 8;
|
||||
bits += (length - remainder);
|
||||
for(i=0; i<rbits; i++) {
|
||||
if((bits[i]&1) != 0) {
|
||||
printf("Terminating code includes 1-bit.\n");
|
||||
printBinary(bits, remainder);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
p = bits + rbits;
|
||||
for(i=0; i<words; i++) {
|
||||
v = (unsigned char)bitToInt(p, 8);
|
||||
if(v != ((i&1)?0x11:0xec)) {
|
||||
printf("Remainder codewords wrong.\n");
|
||||
printBinary(bits, remainder);
|
||||
return -1;
|
||||
}
|
||||
p += 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QRdata *QRcode_decodeBits(QRcode *code)
|
||||
{
|
||||
BitStream *bstream;
|
||||
unsigned char *unmasked;
|
||||
int spec[5];
|
||||
int ret, version, mask;
|
||||
int length;
|
||||
QRecLevel level;
|
||||
QRdata *qrdata;
|
||||
|
||||
version = QRcode_decodeVersion(code);
|
||||
if(version < 1) return NULL;
|
||||
ret = QRcode_decodeFormat(code, &level, &mask);
|
||||
if(ret < 0) return NULL;
|
||||
|
||||
QRspec_getEccSpec(version, level, spec);
|
||||
length = QRspec_rsDataLength(spec) * 8;
|
||||
|
||||
unmasked = unmask(code, level, mask);
|
||||
if(unmasked == NULL) return NULL;
|
||||
|
||||
bstream = extractBits(code->width, unmasked, spec);
|
||||
free(unmasked);
|
||||
|
||||
qrdata = QRdata_new();
|
||||
qrdata->version = version;
|
||||
qrdata->level = level;
|
||||
ret = QRdata_decodeBitStream(qrdata, bstream);
|
||||
if(ret > 0) {
|
||||
checkRemainderWords(length, bstream->data, ret);
|
||||
}
|
||||
|
||||
BitStream_free(bstream);
|
||||
|
||||
return qrdata;
|
||||
}
|
||||
|
||||
void QRdata_concatChunks(QRdata *qrdata)
|
||||
{
|
||||
qrdata->data = DataChunk_concatChunkList(qrdata->chunks, &qrdata->size);
|
||||
}
|
||||
|
||||
QRdata *QRcode_decode(QRcode *code)
|
||||
{
|
||||
QRdata *qrdata;
|
||||
|
||||
qrdata = QRcode_decodeBits(code);
|
||||
QRdata_concatChunks(qrdata);
|
||||
|
||||
return qrdata;
|
||||
}
|
||||
|
||||
/*
|
||||
* Micro QR Code decoder
|
||||
*/
|
||||
|
||||
struct FormatInfo MQRformat[] = {
|
||||
{1, QR_ECLEVEL_L},
|
||||
{2, QR_ECLEVEL_L},
|
||||
{2, QR_ECLEVEL_M},
|
||||
{3, QR_ECLEVEL_L},
|
||||
{3, QR_ECLEVEL_M},
|
||||
{4, QR_ECLEVEL_L},
|
||||
{4, QR_ECLEVEL_M},
|
||||
{4, QR_ECLEVEL_Q}
|
||||
};
|
||||
|
||||
int QRcode_decodeFormatMQR(QRcode *code, int *version, QRecLevel *level, int *mask)
|
||||
{
|
||||
unsigned int v, t;
|
||||
int i, width;
|
||||
unsigned char *p;
|
||||
|
||||
width = code->width;
|
||||
|
||||
v = 0;
|
||||
p = code->data + width * 8 + 1;
|
||||
for(i=0; i<8; i++) {
|
||||
v = v << 1;
|
||||
v |= p[i] & 1;
|
||||
}
|
||||
p = code->data + width * 7 + 8;
|
||||
for(i=0; i<7; i++) {
|
||||
v = v << 1;
|
||||
v |= *(p - width * i) & 1;
|
||||
}
|
||||
v ^= 0x4445;
|
||||
*mask = (v >> 10) & 3;
|
||||
t = (v >> 12) & 7;
|
||||
*version = MQRformat[t].version;
|
||||
*level = MQRformat[t].level;
|
||||
if(*version * 2 + 9 != width) {
|
||||
printf("Decoded version number does not match to the size.\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *unmaskMQR(QRcode *code, QRecLevel level, int mask)
|
||||
{
|
||||
unsigned char *unmasked;
|
||||
|
||||
unmasked = MMask_makeMask(code->version, code->data, mask, level);
|
||||
|
||||
return unmasked;
|
||||
}
|
||||
|
||||
unsigned char *QRcode_unmaskMQR(QRcode *code)
|
||||
{
|
||||
int ret, version, mask;
|
||||
QRecLevel level;
|
||||
|
||||
ret = QRcode_decodeFormatMQR(code, &version, &level, &mask);
|
||||
if(ret < 0) return NULL;
|
||||
|
||||
return unmaskMQR(code, level, mask);
|
||||
}
|
||||
|
||||
static BitStream *extractBitsMQR(int width, unsigned char *frame, int version, QRecLevel level)
|
||||
{
|
||||
BitStream *bstream;
|
||||
unsigned char *bits;
|
||||
FrameFiller *filler;
|
||||
int i;
|
||||
int size;
|
||||
|
||||
size = MQRspec_getDataLengthBit(version, level) + MQRspec_getECCLength(version, level) * 8;
|
||||
bits = (unsigned char *)malloc((size_t)size);
|
||||
filler = FrameFiller_new(width, frame, 1);
|
||||
for(i=0; i<size; i++) {
|
||||
bits[i] = *(FrameFiller_next(filler)) & 1;
|
||||
}
|
||||
free(filler);
|
||||
|
||||
bstream = BitStream_newWithBits((size_t)size, bits);
|
||||
free(bits);
|
||||
|
||||
return bstream;
|
||||
}
|
||||
|
||||
BitStream *QRcode_extractBitsMQR(QRcode *code, int *dataLength, int *eccLength, int *version, QRecLevel *level)
|
||||
{
|
||||
BitStream *bstream;
|
||||
unsigned char *unmasked;
|
||||
int ret, mask;
|
||||
|
||||
ret = QRcode_decodeFormatMQR(code, version, level, &mask);
|
||||
if(ret < 0) return NULL;
|
||||
|
||||
unmasked = unmaskMQR(code, *level, mask);
|
||||
if(unmasked == NULL) return NULL;
|
||||
|
||||
*dataLength = MQRspec_getDataLengthBit(*version, *level);
|
||||
*eccLength = MQRspec_getECCLength(*version, *level) * 8;
|
||||
bstream = extractBitsMQR(code->width, unmasked, *version, *level);
|
||||
free(unmasked);
|
||||
|
||||
return bstream;
|
||||
}
|
||||
|
||||
static int checkRemainderWordsMQR(int length, unsigned char *bits, int remainder, int version)
|
||||
{
|
||||
int rbits, words, paddings;
|
||||
unsigned char *p, v;
|
||||
int i, decoded;
|
||||
|
||||
decoded = length - remainder;
|
||||
bits += decoded;
|
||||
words = (decoded + 7) / 8;
|
||||
rbits = words * 8 - decoded;
|
||||
for(i=0; i<rbits; i++) {
|
||||
if((bits[i]&1) != 0) {
|
||||
printf("Terminating code includes 1-bit.\n");
|
||||
printBinary(bits, remainder);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
paddings = (length - words * 8) / 8;
|
||||
p = bits + rbits;
|
||||
for(i=0; i<paddings; i++) {
|
||||
v = (unsigned char)bitToInt(p, 8);
|
||||
if(v != ((i&1)?0x11:0xec)) {
|
||||
printf("Remainder codewords wrong.\n");
|
||||
printBinary(bits, remainder);
|
||||
return -1;
|
||||
}
|
||||
p += 8;
|
||||
}
|
||||
rbits = length - (paddings + words)* 8;
|
||||
if(rbits > 0) {
|
||||
if((version == 1 || version == 3) && rbits == 4) {
|
||||
v = (unsigned char)bitToInt(p, 4);
|
||||
if(v != 0) {
|
||||
printf("Last padding bits include 1-bit.\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
printf("The length of the last padding bits is %d, not %d.\n", rbits, (version == 1 || version == 3)?4:0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QRdata *QRcode_decodeBitsMQR(QRcode *code)
|
||||
{
|
||||
BitStream *bstream;
|
||||
int ret, version, dataLength, eccLength;
|
||||
QRecLevel level;
|
||||
QRdata *qrdata;
|
||||
|
||||
bstream = QRcode_extractBitsMQR(code, &dataLength, &eccLength, &version, &level);
|
||||
if(bstream == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qrdata = QRdata_newMQR();
|
||||
qrdata->version = version;
|
||||
qrdata->level = level;
|
||||
ret = QRdata_decodeBits(qrdata, dataLength, bstream->data);
|
||||
if(ret > 0) {
|
||||
ret = checkRemainderWordsMQR(dataLength, bstream->data, ret, version);
|
||||
if(ret < 0) {
|
||||
QRdata_free(qrdata);
|
||||
qrdata = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BitStream_free(bstream);
|
||||
|
||||
return qrdata;
|
||||
}
|
||||
|
||||
QRdata *QRcode_decodeMQR(QRcode *code)
|
||||
{
|
||||
QRdata *qrdata;
|
||||
qrdata = QRcode_decodeBitsMQR(code);
|
||||
if(qrdata != NULL) {
|
||||
QRdata_concatChunks(qrdata);
|
||||
}
|
||||
|
||||
return qrdata;
|
||||
}
|
||||
Reference in New Issue
Block a user