diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:43:19 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:43:19 +0300 |
| commit | 5c7048091e3a191e8a34f26852a8976b254e339b (patch) | |
| tree | f1008a55d8ecb3304b5f51ea549156eaba21843b /genqrcode/tests/decoder.c | |
| parent | 5fad10f89c485cfdc7b99011f07609f8871160d4 (diff) | |
| parent | 49980df270e6a39738a0c886c1eef6b42e782edb (diff) | |
| download | Project-Tick-5c7048091e3a191e8a34f26852a8976b254e339b.tar.gz Project-Tick-5c7048091e3a191e8a34f26852a8976b254e339b.zip | |
Add 'genqrcode/' from commit '49980df270e6a39738a0c886c1eef6b42e782edb'
git-subtree-dir: genqrcode
git-subtree-mainline: 5fad10f89c485cfdc7b99011f07609f8871160d4
git-subtree-split: 49980df270e6a39738a0c886c1eef6b42e782edb
Diffstat (limited to 'genqrcode/tests/decoder.c')
| -rw-r--r-- | genqrcode/tests/decoder.c | 953 |
1 files changed, 953 insertions, 0 deletions
diff --git a/genqrcode/tests/decoder.c b/genqrcode/tests/decoder.c new file mode 100644 index 0000000000..706dc31e40 --- /dev/null +++ b/genqrcode/tests/decoder.c @@ -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; +} |
