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:
2026-04-17 00:04:40 +01:00
parent dc68822bcb
commit 6f1a1a274e
98 changed files with 25917 additions and 42 deletions
@@ -0,0 +1,81 @@
add_library(common
common.c common.h)
target_link_libraries(common qrencode)
add_library(rscode
rscode.c rscode.h)
target_link_libraries(rscode common)
macro(MAKE_TEST test_name)
set(ADDITIONAL_LIBS "${ARGN}")
add_executable(${test_name} ${test_name}.c)
target_link_libraries(${test_name} common ${ADDITIONAL_LIBS})
add_test(${test_name} ${test_name})
endmacro(MAKE_TEST)
if(TARGET PNG::PNG)
add_executable(create_frame_pattern create_frame_pattern.c)
target_link_libraries(create_frame_pattern common PNG::PNG)
add_executable(create_mqr_frame_pattern create_mqr_frame_pattern.c)
target_link_libraries(create_mqr_frame_pattern common PNG::PNG)
endif()
if(HAVE_SDL)
add_executable(view_qrcode view_qrcode.c)
target_link_libraries(view_qrcode common)
endif(HAVE_SDL)
if(TARGET Threads::Threads)
if(HAVE_SYS_TIME_H)
add_definitions(-DHAVE_SYS_TIME_H)
endif()
if(HAVE_TIME_H)
add_definitions(-DHAVE_TIME_H)
endif()
add_executable(prof_qrencode prof_qrencode.c)
target_link_libraries(prof_qrencode common Threads::Threads)
if(HAVE_PTHREAD_H)
add_executable(pthread_qrencode pthread_qrencode.c)
target_link_libraries(pthread_qrencode common Threads::Threads)
endif()
endif()
MAKE_TEST(test_bitstream)
MAKE_TEST(test_estimatebit)
MAKE_TEST(test_split)
if(TARGET ICONV::ICONV)
add_library(decoder STATIC
decoder.c decoder.h
datachunk.c datachunk.h
rsecc_decoder.c rsecc_decoder.h)
target_link_libraries(decoder ICONV::ICONV)
MAKE_TEST(test_qrinput decoder)
MAKE_TEST(test_qrspec decoder)
target_compile_definitions(test_qrspec PRIVATE -DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}/")
MAKE_TEST(test_mqrspec decoder)
MAKE_TEST(test_qrencode decoder)
MAKE_TEST(test_split_urls decoder)
MAKE_TEST(test_monkey decoder)
include(CheckCSourceCompiles)
check_c_source_compiles(
"int main(){
const int w = 1;
char buf[w];
return 0;
}"
FIXED_SIZE_BUFFER_INITIALIZATION)
if(FIXED_SIZE_BUFFER_INITIALIZATION)
MAKE_TEST(test_mask decoder)
MAKE_TEST(test_mmask decoder)
MAKE_TEST(test_rs rscode decoder)
endif()
endif()
@@ -0,0 +1,86 @@
AM_CFLAGS =
AM_LDFLAGS =
if HAVE_SDL
sdlPROGRAMS = view_qrcode
AM_CFLAGS += $(SDL_CFLAGS)
AM_LDFLAGS += $(SDL_LIBS)
endif
if HAVE_PNG
pngPROGRAMS = create_frame_pattern create_mqr_frame_pattern
endif
check_PROGRAMS = test_qrinput test_bitstream test_estimatebit test_qrspec \
test_rs test_qrencode test_mqrspec test_split test_mask \
test_mmask test_split_urls test_monkey
noinst_PROGRAMS = $(pngPROGRAMS) $(sdlPROGRAMS) $(check_PROGRAMS) prof_qrencode
noinst_LIBRARIES = libdecoder.a
DECODER_LIBS = libdecoder.a $(LIBICONV)
noinst_HEADERS = common.h rscode.h
if HAVE_LIBPTHREAD
noinst_PROGRAMS += pthread_qrencode
endif
TESTS = $(check_PROGRAMS)
EXTRA_DIST = test_all.sh test_basic.sh test_configure.sh frame URI_testset.inc CMakeLists.txt
libdecoder_a_SOURCES = decoder.c decoder.h datachunk.c datachunk.h rsecc_decoder.c rsecc_decoder.h
test_qrinput_SOURCES = test_qrinput.c common.c
test_qrinput_LDADD = $(DECODER_LIBS) ../libqrencode.la
test_bitstream_SOURCES = test_bitstream.c common.c
test_bitstream_LDADD = ../libqrencode.la
test_estimatebit_SOURCES = test_estimatebit.c common.c
test_estimatebit_LDADD = ../libqrencode.la
test_qrspec_SOURCES = test_qrspec.c common.c
test_qrspec_CPPFLAGS = -DSRCDIR=\"$(srcdir)/\"
test_qrspec_LDADD = $(DECODER_LIBS) ../libqrencode.la
test_mqrspec_SOURCES = test_mqrspec.c common.c
test_mqrspec_LDADD = $(DECODER_LIBS) ../libqrencode.la
test_rs_SOURCES = test_rs.c rscode.c common.c
test_rs_LDADD = $(DECODER_LIBS) ../libqrencode.la
test_qrencode_SOURCES = test_qrencode.c common.c
test_qrencode_LDADD = $(DECODER_LIBS) ../libqrencode.la
test_split_SOURCES = test_split.c common.c
test_split_LDADD = ../libqrencode.la
test_split_urls_SOURCES = test_split_urls.c common.c
test_split_urls_LDADD = $(DECODER_LIBS) ../libqrencode.la
test_monkey_SOURCES = test_monkey.c common.c
test_monkey_LDADD = $(DECODER_LIBS) ../libqrencode.la
test_mask_SOURCES = test_mask.c common.c
test_mask_LDADD = $(DECODER_LIBS) ../libqrencode.la
test_mmask_SOURCES = test_mmask.c common.c
test_mmask_LDADD = $(DECODER_LIBS) ../libqrencode.la
prof_qrencode_SOURCES = prof_qrencode.c common.c
prof_qrencode_LDADD = ../libqrencode.la
pthread_qrencode_SOURCES = pthread_qrencode.c common.c
pthread_qrencode_LDADD = ../libqrencode.la
if HAVE_PNG
create_frame_pattern_SOURCES = create_frame_pattern.c common.c
create_frame_pattern_CFLAGS = $(png_CFLAGS) $(AM_CFLAGS)
create_frame_pattern_LDADD = ../libqrencode.la $(png_LIBS)
create_mqr_frame_pattern_SOURCES = create_mqr_frame_pattern.c common.c
create_mqr_frame_pattern_CFLAGS = $(png_CFLAGS) $(AM_CFLAGS)
create_mqr_frame_pattern_LDADD = ../libqrencode.la $(png_LIBS)
endif
if HAVE_SDL
view_qrcode_SOURCES = view_qrcode.c common.c
view_qrcode_LDADD = ../libqrencode.la
endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,290 @@
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
static int tests = 0;
static int failed = 0;
int assertionFailed = 0;
int assertionNum = 0;
static const char *testName = NULL;
static const char *testFunc = NULL;
const char levelChar[4] = {'L', 'M', 'Q', 'H'};
const char *modeStr[5] = {"nm", "an", "8", "kj", "st"};
int ncmpBin(char *correct, BitStream *bstream, size_t len)
{
int bit;
size_t i;
char *p;
if(len != BitStream_size(bstream)) {
printf("Length is not match: %zu, %zu expected.\n", BitStream_size(bstream), len);
return -1;
}
p = correct;
i = 0;
while(*p != '\0') {
while(*p == ' ') {
p++;
}
bit = (*p == '1')?1:0;
if(bstream->data[i] != bit) return -1;
i++;
p++;
if(i == len) break;
}
return 0;
}
int cmpBin(char *correct, BitStream *bstream)
{
size_t len = 0;
char *p;
for(p = correct; *p != '\0'; p++) {
if(*p != ' ') len++;
}
return ncmpBin(correct, bstream, len);
}
void testInit(int tests)
{
printf("1..%d\n", tests);
}
void testStartReal(const char *func, const char *name)
{
tests++;
testName = name;
testFunc = func;
assertionFailed = 0;
assertionNum = 0;
//printf("_____%d: %s: %s...\n", tests, func, name);
}
void testEnd(int result)
{
if(result) {
printf("not ok %d %s: %s\n", tests, testFunc, testName);
failed++;
} else {
printf("ok %d %s: %s\n", tests, testFunc, testName);
}
}
void testFinish(void)
{
if(assertionFailed) {
printf("not ok %d %s: %s (%d assertions failed.)\n", tests, testFunc, testName, assertionFailed);
failed++;
} else {
printf("ok %d %s: %s (%d assertions passed.)\n", tests, testFunc, testName, assertionNum);
}
}
void testReport(int expectedTests)
{
printf("Total %d tests, %d fails.\n", tests, failed);
if(failed) exit(-1);
if(expectedTests != tests) {
printf("WARNING: the number of the executed tests (%d) is not equal to the expecetd (%d).\n", tests, expectedTests);
}
}
int testNum(void)
{
return tests;
}
void printBinary(unsigned char *data, int length)
{
int i;
for(i=0; i<length; i++) {
printf(data[i]?"1":"0");
}
printf("\n");
}
void printBstream(BitStream *bstream)
{
printBinary(bstream->data, BitStream_size(bstream));
}
void printQRinput(QRinput *input)
{
QRinput_List *list;
int i;
list = input->head;
while(list != NULL) {
for(i=0; i<list->size; i++) {
printf("0x%02x,", list->data[i]);
}
list = list->next;
}
printf("\n");
}
void printQRinputInfo(QRinput *input)
{
QRinput_List *list;
BitStream *b;
int i, ret;
printf("QRinput info:\n");
printf(" version: %d\n", input->version);
printf(" level : %c\n", levelChar[input->level]);
list = input->head;
i = 0;
while(list != NULL) {
i++;
list = list->next;
}
printf(" chunks: %d\n", i);
b = BitStream_new();
ret = QRinput_mergeBitStream(input, b);
if(ret == 0) {
printf(" bitstream-size: %zu\n", BitStream_size(b));
BitStream_free(b);
}
list = input->head;
i = 0;
while(list != NULL) {
printf("\t#%d: mode = %s, size = %d\n", i, modeStr[list->mode], list->size);
i++;
list = list->next;
}
}
void printQRinputStruct(QRinput_Struct *s)
{
QRinput_InputList *list;
int i = 1;
printf("Struct size: %d\n", s->size);
printf("Struct parity: %08x\n", s->parity);
for(list = s->head; list != NULL; list = list->next) {
printf("Symbol %d - ", i);
printQRinputInfo(list->input);
i++;
}
}
void printFrame(int width, unsigned char *frame)
{
int x, y;
for(y=0; y<width; y++) {
for(x=0; x<width; x++) {
printf("%02x ", *frame++);
}
printf("\n");
}
}
void printQRcode(QRcode *code)
{
printFrame(code->width, code->data);
}
void printQRRawCodeFromQRinput(QRinput *input)
{
QRRawCode *raw;
int i;
puts("QRRawCode dump image:");
raw = QRraw_new(input);
if(raw == NULL) {
puts("Failed to generate QRRawCode from this input.\n");
return;
}
for(i=0; i<raw->dataLength; i++) {
printf(" %02x", raw->datacode[i]);
}
for(i=0; i<raw->eccLength; i++) {
printf(" %02x", raw->ecccode[i]);
}
printf("\n");
QRraw_free(raw);
}
#if HAVE_SDL
/* Experimental debug function */
/* You can call show_QRcode(QRcode *code) to display the QR Code from anywhere
* in test code using SDL. */
#include <SDL.h>
static void draw_QRcode(QRcode *qrcode, int ox, int oy, int margin, int size, SDL_Surface *surface)
{
int x, y, width;
unsigned char *p;
SDL_Rect rect;
Uint32 color[2];
color[0] = SDL_MapRGBA(surface->format, 255, 255, 255, 255);
color[1] = SDL_MapRGBA(surface->format, 0, 0, 0, 255);
SDL_FillRect(surface, NULL, color[0]);
ox += margin * size;
oy += margin * size;
width = qrcode->width;
p = qrcode->data;
for(y=0; y<width; y++) {
for(x=0; x<width; x++) {
rect.x = ox + x * size;
rect.y = oy + y * size;
rect.w = size;
rect.h = size;
SDL_FillRect(surface, &rect, color[*p&1]);
p++;
}
}
}
void show_QRcode(QRcode *qrcode)
{
SDL_Event event;
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Surface *surface;
SDL_Texture *texture;
if(!SDL_WasInit(SDL_INIT_VIDEO)) {
SDL_Init(SDL_INIT_VIDEO);
atexit(SDL_Quit);
}
int width = (qrcode->width + 4 * 2) * 4; //maring = 4, size = 4
SDL_CreateWindowAndRenderer(width, width, SDL_WINDOW_SHOWN, &window, &renderer);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
surface = SDL_CreateRGBSurface(0, width, width, 32, 0, 0, 0, 0);
draw_QRcode(qrcode, 0, 0, 4, 4, surface);
texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
fprintf(stderr, "Press any key on the QR Code window to proceed.\n");
int loop = 1;
while(loop) {
SDL_WaitEvent(&event);
if(event.type == SDL_KEYDOWN) {
loop = 0;
}
}
SDL_FreeSurface(surface);
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
}
#else
void show_QRcode(QRcode *qrcode) {
}
#endif
@@ -0,0 +1,56 @@
/*
* common part of test units.
*/
#ifndef COMMON_H__
#define COMMON_H__
#include <stdlib.h>
#if HAVE_CONFIG_H
#include "../config.h"
#endif
#include "../qrencode.h"
#include "../qrinput.h"
#include "../bitstream.h"
#include "../qrencode_inner.h"
extern int assertionFailed;
extern int assertionNum;
extern const char levelChar[4];
extern const char *modeStr[5];
void testInit(int tests);
#define testStart(__arg__) (testStartReal(__func__, __arg__))
#define testEndExp(__arg__) (testEnd(!(__arg__)))
void testStartReal(const char *func, const char *name);
void testEnd(int result);
void testFinish(void);
void testReport(int tests);
#define assert_exp(__exp__, ...) \
{assertionNum++;if(!(__exp__)) {assertionFailed++; printf(__VA_ARGS__);}}
#define assert_zero(__exp__, ...) assert_exp((__exp__) == 0, __VA_ARGS__)
#define assert_nonzero(__exp__, ...) assert_exp((__exp__) != 0, __VA_ARGS__)
#define assert_null(__ptr__, ...) assert_exp((__ptr__) == NULL, __VA_ARGS__)
#define assert_nonnull(__ptr__, ...) assert_exp((__ptr__) != NULL, __VA_ARGS__)
#define assert_equal(__e1__, __e2__, ...) assert_exp((__e1__) == (__e2__), __VA_ARGS__)
#define assert_notequal(__e1__, __e2__, ...) assert_exp((__e1__) != (__e2__), __VA_ARGS__)
#define assert_nothing(__exp__, ...) {printf(__VA_ARGS__); __exp__;}
int ncmpBin(char *correct, BitStream *bstream, size_t len);
int cmpBin(char *correct, BitStream *bstream);
void printFrame(int width, unsigned char *frame);
void printQRcode(QRcode *code);
void printQRRawCodeFromQRinput(QRinput *input);
void printQRinput(QRinput *input);
void printQRinputInfo(QRinput *input);
void printQRinputStruct(QRinput_Struct *s);
void printBinary(unsigned char *data, int length);
void printBstream(BitStream *bstream);
void show_QRcode(QRcode *qrcode);
#endif /* COMMON_H__ */
@@ -0,0 +1,170 @@
/*
* This tool creates a frame pattern data for debug purpose used by
* test_qrspec. test_qrspec and create_frame_pattern uses the same function
* of libqrencode. This means the test is meaningless if test_qrspec is run
* with a pattern data created by create_frame_pattern of the same version.
* In order to test it correctly, create a pattern data by the tool of the
* previous version, or use the frame data attached to the package.
*/
#include <stdio.h>
#include <string.h>
#include <png.h>
#include "common.h"
#include "../qrspec.h"
void append_pattern(int version, FILE *fp)
{
int width;
unsigned char *frame;
frame = QRspec_newFrame(version);
width = QRspec_getWidth(version);
fwrite(frame, 1, width * width, fp);
free(frame);
}
static int writePNG(unsigned char *frame, int width, const char *outfile)
{
static FILE *fp;
png_structp png_ptr;
png_infop info_ptr;
unsigned char *row, *p, *q;
int x, y, xx, yy, bit;
int realwidth;
const int margin = 0;
const int size = 1;
realwidth = (width + margin * 2) * size;
row = (unsigned char *)malloc((realwidth + 7) / 8);
if(row == NULL) {
fprintf(stderr, "Failed to allocate memory.\n");
exit(EXIT_FAILURE);
}
if(outfile[0] == '-' && outfile[1] == '\0') {
fp = stdout;
} else {
fp = fopen(outfile, "wb");
if(fp == NULL) {
fprintf(stderr, "Failed to create file: %s\n", outfile);
perror(NULL);
exit(EXIT_FAILURE);
}
}
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(png_ptr == NULL) {
fclose(fp);
fprintf(stderr, "Failed to initialize PNG writer.\n");
exit(EXIT_FAILURE);
}
info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == NULL) {
fclose(fp);
fprintf(stderr, "Failed to initialize PNG write.\n");
exit(EXIT_FAILURE);
}
if(setjmp(png_jmpbuf(png_ptr))) {
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
fprintf(stderr, "Failed to write PNG image.\n");
exit(EXIT_FAILURE);
}
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr,
realwidth, realwidth,
1,
PNG_COLOR_TYPE_GRAY,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
/* top margin */
memset(row, 0xff, (realwidth + 7) / 8);
for(y=0; y<margin * size; y++) {
png_write_row(png_ptr, row);
}
/* data */
p = frame;
for(y=0; y<width; y++) {
bit = 7;
memset(row, 0xff, (realwidth + 7) / 8);
q = row;
q += margin * size / 8;
bit = 7 - (margin * size % 8);
for(x=0; x<width; x++) {
for(xx=0; xx<size; xx++) {
*q ^= (*p & 1) << bit;
bit--;
if(bit < 0) {
q++;
bit = 7;
}
}
p++;
}
for(yy=0; yy<size; yy++) {
png_write_row(png_ptr, row);
}
}
/* bottom margin */
memset(row, 0xff, (realwidth + 7) / 8);
for(y=0; y<margin * size; y++) {
png_write_row(png_ptr, row);
}
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
free(row);
return 0;
}
void write_pattern_image(int version, const char *filename)
{
int width;
unsigned char *frame;
static char str[256];
frame = QRspec_newFrame(version);
width = QRspec_getWidth(version);
snprintf(str, 256, "%s-%d.png", filename, version);
writePNG(frame, width, str);
free(frame);
}
void write_pattern(const char *filename)
{
FILE *fp;
int i;
fp = fopen(filename, "wb");
if(fp == NULL) {
perror("Failed to open a file to write:");
abort();
}
for(i=1; i<=QRSPEC_VERSION_MAX; i++) {
append_pattern(i, fp);
write_pattern_image(i, filename);
}
fclose(fp);
}
int main(int argc, char **argv)
{
if(argc < 2) {
printf("Create empty frame patterns.\nUsage: %s FILENAME\n", argv[0]);
exit(0);
}
write_pattern(argv[1]);
return 0;
}
@@ -0,0 +1,170 @@
/*
* This tool creates a frame pattern data for debug purpose used by
* test_qrspec. test_qrspec and create_frame_pattern uses the same function
* of libqrencode. This means the test is meaningless if test_qrspec is run
* with a pattern data created by create_frame_pattern of the same version.
* In order to test it correctly, create a pattern data by the tool of the
* previous version, or use the frame data attached to the package.
*/
#include <stdio.h>
#include <string.h>
#include <png.h>
#include "common.h"
#include "../mqrspec.h"
void append_pattern(int version, FILE *fp)
{
int width;
unsigned char *frame;
frame = MQRspec_newFrame(version);
width = MQRspec_getWidth(version);
fwrite(frame, 1, width * width, fp);
free(frame);
}
static int writePNG(unsigned char *frame, int width, const char *outfile)
{
static FILE *fp;
png_structp png_ptr;
png_infop info_ptr;
unsigned char *row, *p, *q;
int x, y, xx, yy, bit;
int realwidth;
const int margin = 0;
const int size = 1;
realwidth = (width + margin * 2) * size;
row = (unsigned char *)malloc((realwidth + 7) / 8);
if(row == NULL) {
fprintf(stderr, "Failed to allocate memory.\n");
exit(EXIT_FAILURE);
}
if(outfile[0] == '-' && outfile[1] == '\0') {
fp = stdout;
} else {
fp = fopen(outfile, "wb");
if(fp == NULL) {
fprintf(stderr, "Failed to create file: %s\n", outfile);
perror(NULL);
exit(EXIT_FAILURE);
}
}
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(png_ptr == NULL) {
fclose(fp);
fprintf(stderr, "Failed to initialize PNG writer.\n");
exit(EXIT_FAILURE);
}
info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == NULL) {
fclose(fp);
fprintf(stderr, "Failed to initialize PNG write.\n");
exit(EXIT_FAILURE);
}
if(setjmp(png_jmpbuf(png_ptr))) {
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
fprintf(stderr, "Failed to write PNG image.\n");
exit(EXIT_FAILURE);
}
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr,
realwidth, realwidth,
1,
PNG_COLOR_TYPE_GRAY,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
/* top margin */
memset(row, 0xff, (realwidth + 7) / 8);
for(y=0; y<margin * size; y++) {
png_write_row(png_ptr, row);
}
/* data */
p = frame;
for(y=0; y<width; y++) {
bit = 7;
memset(row, 0xff, (realwidth + 7) / 8);
q = row;
q += margin * size / 8;
bit = 7 - (margin * size % 8);
for(x=0; x<width; x++) {
for(xx=0; xx<size; xx++) {
*q ^= (*p & 1) << bit;
bit--;
if(bit < 0) {
q++;
bit = 7;
}
}
p++;
}
for(yy=0; yy<size; yy++) {
png_write_row(png_ptr, row);
}
}
/* bottom margin */
memset(row, 0xff, (realwidth + 7) / 8);
for(y=0; y<margin * size; y++) {
png_write_row(png_ptr, row);
}
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
free(row);
return 0;
}
void write_pattern_image(int version, const char *filename)
{
int width;
unsigned char *frame;
static char str[256];
frame = MQRspec_newFrame(version);
width = MQRspec_getWidth(version);
snprintf(str, 256, "%s-M%d.png", filename, version);
writePNG(frame, width, str);
free(frame);
}
void write_pattern(const char *filename)
{
FILE *fp;
int i;
fp = fopen(filename, "wb");
if(fp == NULL) {
perror("Failed to open a file to write:");
abort();
}
for(i=1; i<=MQRSPEC_VERSION_MAX; i++) {
append_pattern(i, fp);
write_pattern_image(i, filename);
}
fclose(fp);
}
int main(int argc, char **argv)
{
if(argc < 2) {
printf("Create empty frame patterns.\nUsage: %s FILENAME\n", argv[0]);
exit(0);
}
write_pattern(argv[1]);
return 0;
}
@@ -0,0 +1,174 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iconv.h>
#include "datachunk.h"
DataChunk *DataChunk_new(QRencodeMode mode)
{
DataChunk *chunk;
chunk = (DataChunk *)calloc(1, sizeof(DataChunk));
if(chunk == NULL) return NULL;
chunk->mode = mode;
return chunk;
}
void DataChunk_free(DataChunk *chunk)
{
if(chunk) {
if(chunk->data) free(chunk->data);
free(chunk);
}
}
void DataChunk_freeList(DataChunk *list)
{
DataChunk *next;
while(list != NULL) {
next = list->next;
DataChunk_free(list);
list = next;
}
}
static void dumpNum(DataChunk *chunk)
{
printf("%s\n", chunk->data);
}
static void dumpAn(DataChunk *chunk)
{
printf("%s\n", chunk->data);
}
static void dump8(DataChunk *chunk)
{
int i, j;
unsigned char c;
int count = 0;
unsigned char buf[16];
for(i=0; i<chunk->size; i++) {
buf[count] = chunk->data[i];
c = chunk->data[i];
if(c >= ' ' && c <= '~') {
putchar(c);
} else {
putchar('.');
}
count++;
if(count >= 16) {
putchar(' ');
for(j=0; j<16; j++) {
printf(" %02x", buf[j]);
}
count = 0;
putchar('\n');
}
}
if(count > 0) {
for(i=0; i<16 - count; i++) {
putchar(' ');
}
putchar(' ');
for(j=0; j<count; j++) {
printf(" %02x", buf[j]);
}
count = 0;
putchar('\n');
}
}
static void dumpKanji(DataChunk *chunk)
{
iconv_t conv;
char *inbuf, *outbuf, *outp;
size_t inbytes, outbytes, ret;
conv = iconv_open("UTF-8", "SHIFT_JIS");
inbytes = chunk->size;
inbuf = (char *)chunk->data;
outbytes = inbytes * 4 + 1;
outbuf = (char *)malloc(inbytes * 4 + 1);
outp = outbuf;
ret = iconv(conv, &inbuf, &inbytes, &outp, &outbytes);
if(ret == (size_t) -1) { perror(NULL); }
*outp = '\0';
printf("%s\n", outbuf);
iconv_close(conv);
free(outbuf);
}
static void dumpChunk(DataChunk *chunk)
{
switch(chunk->mode) {
case QR_MODE_NUM:
printf("Numeric: %d bytes\n", chunk->size);
dumpNum(chunk);
break;
case QR_MODE_AN:
printf("AlphaNumeric: %d bytes\n", chunk->size);
dumpAn(chunk);
break;
case QR_MODE_8:
printf("8-bit data: %d bytes\n", chunk->size);
dump8(chunk);
break;
case QR_MODE_KANJI:
printf("Kanji: %d bytes\n", chunk->size);
dumpKanji(chunk);
break;
default:
printf("Invalid or reserved: %d bytes\n", chunk->size);
dump8(chunk);
break;
}
}
void DataChunk_dumpChunkList(DataChunk *list)
{
while(list != NULL) {
dumpChunk(list);
list = list->next;
}
}
int DataChunk_totalSize(DataChunk *list)
{
int size = 0;
while(list != NULL) {
size += list->size;
list = list->next;
}
return size;
}
unsigned char *DataChunk_concatChunkList(DataChunk *list, int *retsize)
{
int size, idx;
unsigned char *data;
size = DataChunk_totalSize(list);
if(size <= 0) return NULL;
data = (unsigned char *)malloc(size + 1);
idx = 0;
while(list != NULL) {
memcpy(&data[idx], list->data, list->size);
idx += list->size;
list = list->next;
}
data[size] = '\0';
*retsize = size;
return data;
}
@@ -0,0 +1,21 @@
#ifndef DATACHUNK_H
#define DATACHUNK_H
#include "../qrencode.h"
typedef struct _DataChunk {
QRencodeMode mode;
int size;
int bits;
unsigned char *data;
struct _DataChunk *next;
} DataChunk;
DataChunk *DataChunk_new(QRencodeMode mode);
void DataChunk_free(DataChunk *chunk);
void DataChunk_freeList(DataChunk *list);
void DataChunk_dumpChunkList(DataChunk *list);
int DataChunk_totalSize(DataChunk *list);
unsigned char *DataChunk_concatChunkList(DataChunk *list, int *retsize);
#endif /* DATACHUNK_H */
@@ -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;
}
@@ -0,0 +1,43 @@
#ifndef DECODER_H
#define DECODER_H
#include "../qrencode.h"
#include "datachunk.h"
typedef struct {
unsigned char *data;
int size;
int mqr;
int version;
QRecLevel level;
DataChunk *chunks, *last;
int eccResult;
} QRdata;
struct FormatInfo {
int version;
QRecLevel level;
};
extern struct FormatInfo MQRformat[];
QRdata *QRdata_new(void);
QRdata *QRdata_newMQR(void);
int QRdata_decodeBitStream(QRdata *qrdata, BitStream *bstream);
void QRdata_dump(QRdata *data);
void QRdata_free(QRdata *data);
int QRcode_decodeVersion(QRcode *code);
int QRcode_decodeFormat(QRcode *code, QRecLevel *level, int *mask);
unsigned char *QRcode_unmask(QRcode *code);
BitStream *QRcode_extractBits(QRcode *code, int *dataLength, int *eccLength);
QRdata *QRcode_decodeBits(QRcode *code);
QRdata *QRcode_decode(QRcode *code);
int QRcode_decodeFormatMQR(QRcode *code, int *vesion, QRecLevel *level, int *mask);
unsigned char *QRcode_unmaskMQR(QRcode *code);
BitStream *QRcode_extractBitsMQR(QRcode *code, int *dataLength, int *eccLength, int *version, QRecLevel *level);
QRdata *QRcode_decodeBitsMQR(QRcode *code);
QRdata *QRcode_decodeMQR(QRcode *code);
#endif /* DECODER_H */
Binary file not shown.
@@ -0,0 +1,102 @@
#include <stdio.h>
#include <stdlib.h>
#if HAVE_CONFIG_H
#include "../config.h"
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <errno.h>
#include "../qrencode.h"
#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
static LARGE_INTEGER startTime;
static LARGE_INTEGER frequency = { .QuadPart = 0 };
#else
static struct timeval tv;
#endif
static void timerStart(const char *str)
{
printf("%s: START\n", str);
#ifdef _MSC_VER
(void) QueryPerformanceCounter(&startTime);
#else
gettimeofday(&tv, NULL);
#endif
}
static void timerStop(void)
{
#ifdef _MSC_VER
LARGE_INTEGER endTime, elapsed;
(void) QueryPerformanceCounter(&endTime);
if (frequency.QuadPart == 0) {
(void) QueryPerformanceFrequency(&frequency);
}
elapsed.QuadPart = endTime.QuadPart - startTime.QuadPart;
elapsed.QuadPart *= 1000;
elapsed.QuadPart /= frequency.QuadPart;
printf("STOP: %lld msec\n", elapsed.QuadPart);
#else
struct timeval tc;
gettimeofday(&tc, NULL);
printf("STOP: %ld msec\n", (tc.tv_sec - tv.tv_sec) * 1000
+ (tc.tv_usec - tv.tv_usec) / 1000);
#endif
}
static void prof_ver1to10(void)
{
QRcode *code;
int i;
int version;
static const char *data = "This is test.";
timerStart("Version 1 - 10 (500 symbols for each)");
for(i=0; i<500; i++) {
for(version = 0; version < 11; version++) {
code = QRcode_encodeString(data, version, QR_ECLEVEL_L, QR_MODE_8, 0);
if(code == NULL) {
perror("Failed to encode:");
} else {
QRcode_free(code);
}
}
}
timerStop();
}
static void prof_ver31to40(void)
{
QRcode *code;
int i;
int version;
static const char *data = "This is test.";
timerStart("Version 31 - 40 (50 symbols for each)");
for(i=0; i<50; i++) {
for(version = 31; version < 41; version++) {
code = QRcode_encodeString(data, version, QR_ECLEVEL_L, QR_MODE_8, 0);
if(code == NULL) {
perror("Failed to encode:");
} else {
QRcode_free(code);
}
}
}
timerStop();
}
int main()
{
prof_ver1to10();
prof_ver31to40();
return 0;
}
@@ -0,0 +1,135 @@
#include <stdio.h>
#include <stdlib.h>
#if HAVE_CONFIG_H
#include "../config.h"
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <pthread.h>
#include <errno.h>
#include "../qrencode.h"
#define THREADS (10)
static pthread_t threads[THREADS];
#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
static LARGE_INTEGER startTime;
static LARGE_INTEGER frequency = { .QuadPart = 0 };
#else
static struct timeval tv;
#endif
static void timerStart(const char *str)
{
printf("%s: START\n", str);
#ifdef _MSC_VER
(void) QueryPerformanceCounter(&startTime);
#else
gettimeofday(&tv, NULL);
#endif
}
static void timerStop(void)
{
#ifdef _MSC_VER
LARGE_INTEGER endTime, elapsed;
(void) QueryPerformanceCounter(&endTime);
if (frequency.QuadPart == 0) {
(void) QueryPerformanceFrequency(&frequency);
}
elapsed.QuadPart = endTime.QuadPart - startTime.QuadPart;
elapsed.QuadPart *= 1000;
elapsed.QuadPart /= frequency.QuadPart;
printf("STOP: %lld msec\n", elapsed.QuadPart);
#else
struct timeval tc;
gettimeofday(&tc, NULL);
printf("STOP: %ld msec\n", (tc.tv_sec - tv.tv_sec) * 1000
+ (tc.tv_usec - tv.tv_usec) / 1000);
#endif
}
static void *encode_ver1to10(void *arg)
{
QRcode *code;
int i;
int version;
static const char *data = "This is test.";
for(i=0; i<500; i++) {
for(version = 0; version < 11; version++) {
code = QRcode_encodeString(data, version, QR_ECLEVEL_L, QR_MODE_8, 0);
if(code == NULL) {
perror("Failed to encode:");
} else {
QRcode_free(code);
}
}
}
return NULL;
}
static void prof_ver1to10(void)
{
int i;
timerStart("Version 1 - 10 (500 symbols for each)");
for(i=0; i<THREADS; i++) {
pthread_create(&threads[i], NULL, encode_ver1to10, NULL);
}
for(i=0; i<THREADS; i++) {
pthread_join(threads[i], NULL);
}
timerStop();
}
static void *encode_ver31to40(void *arg)
{
QRcode *code;
int i;
int version;
static const char *data = "This is test.";
for(i=0; i<50; i++) {
for(version = 31; version < 41; version++) {
code = QRcode_encodeString(data, version, QR_ECLEVEL_L, QR_MODE_8, 0);
if(code == NULL) {
perror("Failed to encode:");
} else {
QRcode_free(code);
}
}
}
return NULL;
}
static void prof_ver31to40(void)
{
int i;
timerStart("Version 31 - 40 (50 symbols for each)");
for(i=0; i<THREADS; i++) {
pthread_create(&threads[i], NULL, encode_ver31to40, NULL);
}
for(i=0; i<THREADS; i++) {
pthread_join(threads[i], NULL);
}
timerStop();
}
int main()
{
prof_ver1to10();
prof_ver31to40();
return 0;
}
@@ -0,0 +1,274 @@
/*
* qrencode - QR Code encoder
*
* Reed solomon encoder. This code is taken from Phil Karn's libfec then
* editted and packed into a pair of .c and .h files.
*
* Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
* (libfec is released under the GNU Lesser General Public License.)
*
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "rscode.h"
/* Stuff specific to the 8-bit symbol version of the general purpose RS codecs
*
*/
typedef unsigned char data_t;
/**
* Reed-Solomon codec control block
*/
struct _RS {
int mm; /* Bits per symbol */
int nn; /* Symbols per block (= (1<<mm)-1) */
data_t *alpha_to; /* log lookup table */
data_t *index_of; /* Antilog lookup table */
data_t *genpoly; /* Generator polynomial */
int nroots; /* Number of generator roots = number of parity symbols */
int fcr; /* First consecutive root, index form */
int prim; /* Primitive element, index form */
int iprim; /* prim-th root of 1, index form */
int pad; /* Padding bytes in shortened block */
int gfpoly;
};
static inline int modnn(RS *rs, int x){
while (x >= rs->nn) {
x -= rs->nn;
x = (x >> rs->mm) + (x & rs->nn);
}
return x;
}
#define MODNN(x) modnn(rs,x)
#define MM (rs->mm)
#define NN (rs->nn)
#define ALPHA_TO (rs->alpha_to)
#define INDEX_OF (rs->index_of)
#define GENPOLY (rs->genpoly)
#define NROOTS (rs->nroots)
#define FCR (rs->fcr)
#define PRIM (rs->prim)
#define IPRIM (rs->iprim)
#define PAD (rs->pad)
#define A0 (NN)
/* Initialize a Reed-Solomon codec
* symsize = symbol size, bits
* gfpoly = Field generator polynomial coefficients
* fcr = first root of RS code generator polynomial, index form
* prim = primitive element to generate polynomial roots
* nroots = RS code generator polynomial degree (number of roots)
* pad = padding bytes at front of shortened block
*/
static RS *init_rs_char(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad)
{
RS *rs;
/* Common code for intializing a Reed-Solomon control block (char or int symbols)
* Copyright 2004 Phil Karn, KA9Q
* May be used under the terms of the GNU Lesser General Public License (LGPL)
*/
//#undef NULL
//#define NULL ((void *)0)
int i, j, sr,root,iprim;
rs = NULL;
/* Check parameter ranges */
if(symsize < 0 || symsize > (int)(8*sizeof(data_t))){
goto done;
}
if(fcr < 0 || fcr >= (1<<symsize))
goto done;
if(prim <= 0 || prim >= (1<<symsize))
goto done;
if(nroots < 0 || nroots >= (1<<symsize))
goto done; /* Can't have more roots than symbol values! */
if(pad < 0 || pad >= ((1<<symsize) -1 - nroots))
goto done; /* Too much padding */
rs = (RS *)calloc(1,sizeof(RS));
if(rs == NULL)
goto done;
rs->mm = symsize;
rs->nn = (1<<symsize)-1;
rs->pad = pad;
rs->alpha_to = (data_t *)malloc(sizeof(data_t)*(rs->nn+1));
if(rs->alpha_to == NULL){
free(rs);
rs = NULL;
goto done;
}
rs->index_of = (data_t *)malloc(sizeof(data_t)*(rs->nn+1));
if(rs->index_of == NULL){
free(rs->alpha_to);
free(rs);
rs = NULL;
goto done;
}
/* Generate Galois field lookup tables */
rs->index_of[0] = A0; /* log(zero) = -inf */
rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */
sr = 1;
for(i=0;i<rs->nn;i++){
rs->index_of[sr] = i;
rs->alpha_to[i] = sr;
sr <<= 1;
if(sr & (1<<symsize))
sr ^= gfpoly;
sr &= rs->nn;
}
if(sr != 1){
/* field generator polynomial is not primitive! */
free(rs->alpha_to);
free(rs->index_of);
free(rs);
rs = NULL;
goto done;
}
/* Form RS code generator polynomial from its roots */
rs->genpoly = (data_t *)malloc(sizeof(data_t)*(nroots+1));
if(rs->genpoly == NULL){
free(rs->alpha_to);
free(rs->index_of);
free(rs);
rs = NULL;
goto done;
}
rs->fcr = fcr;
rs->prim = prim;
rs->nroots = nroots;
rs->gfpoly = gfpoly;
/* Find prim-th root of 1, used in decoding */
for(iprim=1;(iprim % prim) != 0;iprim += rs->nn)
;
rs->iprim = iprim / prim;
rs->genpoly[0] = 1;
for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) {
rs->genpoly[i+1] = 1;
/* Multiply rs->genpoly[] by @**(root + x) */
for (j = i; j > 0; j--){
if (rs->genpoly[j] != 0)
rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)];
else
rs->genpoly[j] = rs->genpoly[j-1];
}
/* rs->genpoly[0] can never be zero */
rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)];
}
/* convert rs->genpoly[] to index form for quicker encoding */
for (i = 0; i <= nroots; i++)
rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
done:;
return rs;
}
RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad)
{
return init_rs_char(symsize, gfpoly, fcr, prim, nroots, pad);
}
void free_rs_char(RS *rs)
{
free(rs->alpha_to);
free(rs->index_of);
free(rs->genpoly);
free(rs);
}
/* The guts of the Reed-Solomon encoder, meant to be #included
* into a function body with the following typedefs, macros and variables supplied
* according to the code parameters:
* data_t - a typedef for the data symbol
* data_t data[] - array of NN-NROOTS-PAD and type data_t to be encoded
* data_t parity[] - an array of NROOTS and type data_t to be written with parity symbols
* NROOTS - the number of roots in the RS code generator polynomial,
* which is the same as the number of parity symbols in a block.
Integer variable or literal.
*
* NN - the total number of symbols in a RS block. Integer variable or literal.
* PAD - the number of pad symbols in a block. Integer variable or literal.
* ALPHA_TO - The address of an array of NN elements to convert Galois field
* elements in index (log) form to polynomial form. Read only.
* INDEX_OF - The address of an array of NN elements to convert Galois field
* elements in polynomial form to index (log) form. Read only.
* MODNN - a function to reduce its argument modulo NN. May be inline or a macro.
* GENPOLY - an array of NROOTS+1 elements containing the generator polynomial in index form
* The memset() and memmove() functions are used. The appropriate header
* file declaring these functions (usually <string.h>) must be included by the calling
* program.
* Copyright 2004, Phil Karn, KA9Q
* May be used under the terms of the GNU Lesser General Public License (LGPL)
*/
#undef A0
#define A0 (NN) /* Special reserved value encoding zero in index form */
void encode_rs_char(RS *rs, const data_t *data, data_t *parity)
{
int i, j;
data_t feedback;
memset(parity,0,NROOTS*sizeof(data_t));
for(i=0;i<NN-NROOTS-PAD;i++){
feedback = INDEX_OF[data[i] ^ parity[0]];
if(feedback != A0){ /* feedback term is non-zero */
#ifdef UNNORMALIZED
/* This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
* always be for the polynomials constructed by init_rs()
*/
feedback = MODNN(NN - GENPOLY[NROOTS] + feedback);
#endif
for(j=1;j<NROOTS;j++)
parity[j] ^= ALPHA_TO[MODNN(feedback + GENPOLY[NROOTS-j])];
}
/* Shift */
memmove(&parity[0],&parity[1],sizeof(data_t)*(NROOTS-1));
if(feedback != A0)
parity[NROOTS-1] = ALPHA_TO[MODNN(feedback + GENPOLY[0])];
else
parity[NROOTS-1] = 0;
}
}
@@ -0,0 +1,40 @@
/*
* qrencode - QR Code encoder
*
* Reed solomon encoder. This code is taken from Phil Karn's libfec then
* editted and packed into a pair of .c and .h files.
*
* Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
* (libfec is released under the GNU Lesser General Public License.)
*
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RSCODE_H
#define RSCODE_H
/*
* General purpose RS codec, 8-bit symbols.
*/
typedef struct _RS RS;
extern RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad);
extern void encode_rs_char(RS *rs, const unsigned char *data, unsigned char *parity);
extern void free_rs_char(RS *rs);
#endif /* RSCODE_H */
@@ -0,0 +1,64 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../qrspec.h"
#include "rsecc_decoder.h"
#define SYMBOL_SIZE (8)
#define symbols ((1 << SYMBOL_SIZE) - 1)
static const int proot = 0x11d; /* stands for x^8+x^4+x^3+x^2+1 (see pp.37 of JIS X0510:2004) */
/* min/max codeword length of ECC, calculated from the specification. */
#define min_length (2)
#define max_length (30)
#define max_generatorSize (max_length)
static unsigned char alpha[symbols + 1];
static unsigned char aindex[symbols + 1];
void RSECC_decoder_init() {
int i, b;
alpha[symbols] = 0;
aindex[0] = symbols;
b = 1;
for(i = 0; i < symbols; i++) {
alpha[i] = b;
aindex[b] = i;
b <<= 1;
if(b & (symbols + 1)) {
b ^= proot;
}
b &= symbols;
}
}
int RSECC_decoder_checkSyndrome(int dl, unsigned char *data, int el, unsigned char *ecc)
{
int i, j;
int s;
for(i=0; i<el; i++) {
s = data[0];
for(j=1; j<dl; j++) {
if(s == 0) {
s = data[j];
} else {
s = data[j] ^ alpha[(aindex[s] + i) % symbols];
}
}
for(j=0; j<el; j++) {
if(s == 0) {
s = ecc[j];
} else {
s = ecc[j] ^ alpha[(aindex[s] + i) % symbols];
}
}
if(s != 0) {
return -1;
}
}
return 0;
}
@@ -0,0 +1,7 @@
#ifndef RSECC_DECODER_H
#define RSECC_DECODER_H
void RSECC_decoder_init();
int RSECC_decoder_checkSyndrome(int dl, unsigned char *data, int el, unsigned char *ecc);
#endif /* RSECC_DECODER_H */
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh -e
. ./test_basic.sh
./test_configure.sh
+12
View File
@@ -0,0 +1,12 @@
#!/bin/sh -e
./test_bitstream
./test_estimatebit
./test_qrencode
./test_qrinput
./test_qrspec
./test_rs
./test_split
./test_mask
./test_mqrspec
./test_mmask
./test_monkey
@@ -0,0 +1,257 @@
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "../bitstream.h"
static void test_null(void)
{
BitStream *bstream;
testStart("Empty stream");
bstream = BitStream_new();
assert_zero(BitStream_size(bstream), "Size of empty BitStream is not 0.\n");
assert_null(BitStream_toByte(bstream), "BitStream_toByte returned non-NULL.\n");
assert_nothing(BitStream_free(NULL), "Checking BitStream_free(NULL).\n");
testFinish();
BitStream_free(bstream);
}
static void test_num(void)
{
BitStream *bstream;
unsigned int data = 0x13579bdf;
char correct[] = "0010011010101111001101111011111";
testStart("New from num");
bstream = BitStream_new();
BitStream_appendNum(bstream, 31, data);
testEnd(cmpBin(correct, bstream));
BitStream_free(bstream);
}
static void test_bytes(void)
{
BitStream *bstream;
unsigned char data[1] = {0x3a};
char correct[] = "00111010";
testStart("New from bytes");
bstream = BitStream_new();
BitStream_appendBytes(bstream, 1, data);
testEnd(cmpBin(correct, bstream));
BitStream_free(bstream);
}
static void test_appendNum(void)
{
BitStream *bstream;
char correct[] = "10001010 11111111 11111111 00010010001101000101011001111000";
testStart("Append Num");
bstream = BitStream_new();
BitStream_appendNum(bstream, 8, 0x0000008a);
assert_zero(ncmpBin(correct, bstream, 8), "Internal data is incorrect.\n");
BitStream_appendNum(bstream, 16, 0x0000ffff);
assert_zero(ncmpBin(correct, bstream, 24), "Internal data is incorrect.\n");
BitStream_appendNum(bstream, 32, 0x12345678);
assert_zero(cmpBin(correct, bstream), "Internal data is incorrect.\n");
testFinish();
BitStream_free(bstream);
}
static void test_appendBytes(void)
{
BitStream *bstream;
unsigned char data[8];
char correct[] = "10001010111111111111111100010010001101000101011001111000";
testStart("Append Bytes");
bstream = BitStream_new();
data[0] = 0x8a;
BitStream_appendBytes(bstream, 1, data);
assert_zero(ncmpBin(correct, bstream, 8), "Internal data is incorrect.");
data[0] = 0xff;
data[1] = 0xff;
BitStream_appendBytes(bstream, 2, data);
assert_zero(ncmpBin(correct, bstream, 24), "Internal data is incorrect.\n");
data[0] = 0x12;
data[1] = 0x34;
data[2] = 0x56;
data[3] = 0x78;
BitStream_appendBytes(bstream, 4, data);
assert_zero(cmpBin(correct, bstream), "Internal data is incorrect.\n");
testFinish();
BitStream_free(bstream);
}
static void test_toByte(void)
{
BitStream *bstream;
unsigned char correct[] = {
0x8a, 0xff, 0xff, 0x12, 0x34, 0x56, 0x78
};
unsigned char *result;
testStart("Convert to a byte array");
bstream = BitStream_new();
BitStream_appendBytes(bstream, 1, &correct[0]);
BitStream_appendBytes(bstream, 2, &correct[1]);
BitStream_appendBytes(bstream, 4, &correct[3]);
result = BitStream_toByte(bstream);
testEnd(memcmp(correct, result, 7));
BitStream_free(bstream);
free(result);
}
static void test_toByte_4bitpadding(void)
{
BitStream *bstream;
unsigned char *result;
testStart("Convert to a byte array");
bstream = BitStream_new();
BitStream_appendNum(bstream, 4, 0xb);
result = BitStream_toByte(bstream);
assert_equal(result[0], 0xb0, "incorrect paddings\n");
BitStream_free(bstream);
free(result);
bstream = BitStream_new();
BitStream_appendNum(bstream, 12, 0x335);
result = BitStream_toByte(bstream);
assert_equal(result[0], 0x33, "incorrect paddings\n");
assert_equal(result[1], 0x50, "incorrect paddings\n");
BitStream_free(bstream);
free(result);
testFinish();
}
static void test_size(void)
{
BitStream *bstream;
testStart("size check");
bstream = BitStream_new();
assert_equal(BitStream_size(bstream), 0, "Initialized BitStream is not 0 length");
BitStream_appendNum(bstream, 1, 0);
assert_equal(BitStream_size(bstream), 1, "Size incorrect. (first append)");
BitStream_appendNum(bstream, 2, 0);
assert_equal(BitStream_size(bstream), 3, "Size incorrect. (second append)");
testFinish();
BitStream_free(bstream);
}
static void test_append(void)
{
BitStream *bs1, *bs2;
char c1[] = "00";
char c2[] = "0011";
char c3[] = "01111111111111111";
char c4[] = "001101111111111111111";
char c5[] = "0011011111111111111111111111111111";
int ret;
testStart("Append two BitStreams");
bs1 = BitStream_new();
bs2 = BitStream_new();
ret = BitStream_appendNum(bs1, 1, 0);
ret = BitStream_appendNum(bs2, 1, 0);
ret = BitStream_append(bs1, bs2);
assert_zero(ret, "Failed to append.");
assert_zero(cmpBin(c1, bs1), "Internal data is incorrect.");
ret = BitStream_appendNum(bs1, 2, 3);
assert_zero(ret, "Failed to append.");
assert_zero(cmpBin(c2, bs1), "Internal data is incorrect.");
ret = BitStream_appendNum(bs2, 16, 65535);
assert_zero(ret, "Failed to append.");
assert_zero(cmpBin(c3, bs2), "Internal data is incorrect.");
ret = BitStream_append(bs1, bs2);
assert_zero(ret, "Failed to append.");
assert_zero(cmpBin(c4, bs1), "Internal data is incorrect.");
ret = BitStream_appendNum(bs1, 13, 16383);
assert_zero(ret, "Failed to append.");
assert_zero(cmpBin(c5, bs1), "Internal data is incorrect.");
testFinish();
BitStream_free(bs1);
BitStream_free(bs2);
}
static void test_newWithBits(void)
{
BitStream *bstream;
unsigned char data[4] = {0, 1, 0, 1};
testStart("New with bits");
bstream = BitStream_newWithBits(4, data);
assert_equal(bstream->length, 4, "Internal bit length is incorrect.\n");
assert_equal(bstream->datasize, 4, "Internal buffer size is incorrect.\n");
assert_zero(cmpBin("0101", bstream), "Internal data is incorrect.\n");
testFinish();
BitStream_free(bstream);
}
static void test_newWithBits_size0(void)
{
BitStream *bstream;
testStart("New with bits (size = 0)");
bstream = BitStream_newWithBits(0, NULL);
assert_equal(bstream->length, 0, "Internal bit length is incorrect.\n");
assert_nonzero(bstream->datasize, "Internal buffer size is incorrect.\n");
assert_nonnull(bstream->data, "Internal buffer not allocated.\n");
testFinish();
BitStream_free(bstream);
}
int main()
{
int tests = 11;
testInit(tests);
test_null();
test_num();
test_bytes();
test_appendNum();
test_appendBytes();
test_toByte();
test_toByte_4bitpadding();
test_size();
test_append();
test_newWithBits();
test_newWithBits_size0();
testReport(tests);
return 0;
}
@@ -0,0 +1,61 @@
#!/bin/sh
BASEDIR=..
CONFIG_H_IN="$BASEDIR/config.h.in"
CONFIG_H="$BASEDIR/config.h"
LIBQRENCODE_PC_IN="$BASEDIR/libqrencode.pc.in"
LIBQRENCODE_PC="$BASEDIR/libqrencode.pc"
echo "Testing configure scripts..."
(cd $BASEDIR; ./autogen.sh)
# test config.h.in
grep "#undef HAVE_LIBPTHREAD" $CONFIG_H_IN > /dev/null
if test ! $? -eq 0; then
echo "HAVE_LIBPTHREAD undefined in config.h.in."
exit 1
fi
# test libqrencode.pc.in
grep "Libs.private: @LIBPTHREAD@" $LIBQRENCODE_PC_IN > /dev/null
if test ! $? -eq 0; then
echo "Pthread is not handled in libqrencode.pc.in."
exit 1
fi
# test pthread checks in configure
(cd $BASEDIR; ./configure --with-tests --enable-thread-safety > /dev/null)
grep "#define HAVE_LIBPTHREAD 1" $CONFIG_H > /dev/null
if test ! $? -eq 0; then
echo "HAVE_LIBPTHREAD undefined in config.h."
exit 1
fi
grep "Libs.private: -lpthread" $LIBQRENCODE_PC > /dev/null
if test ! $? -eq 0; then
echo "Pthread is not handled in libqrencode.pc."
exit 1
fi
(cd $BASEDIR; ./configure --with-tests --disable-thread-safety > /dev/null)
grep "#define HAVE_LIBPTHREAD 1" $CONFIG_H > /dev/null
if test ! $? -eq 1; then
echo "HAVE_LIBPTHREAD incorrectly defined in config.h."
exit 1
fi
grep "Libs.private: -lpthread" $LIBQRENCODE_PC > /dev/null
if test ! $? -eq 1; then
echo "Pthread is incorrectly handled in libqrencode.pc."
exit 1
fi
echo "All tests of configure script passed. Now reconfiguring..."
(cd $BASEDIR; ./configure --with-tests > /dev/null)
echo "Done."
exit 0
@@ -0,0 +1,183 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "../qrinput.h"
static QRinput *gstream;
static void test_numbit(void)
{
QRinput *stream;
char num[9]="01234567";
int bits;
testStart("Estimation of Numeric stream (8 digits)");
stream = QRinput_new();
QRinput_append(stream, QR_MODE_NUM, 8, (unsigned char *)num);
bits = QRinput_estimateBitStreamSize(stream, 0);
testEndExp(bits == 41);
QRinput_append(gstream, QR_MODE_NUM, 8, (unsigned char *)num);
QRinput_free(stream);
}
static void test_numbit2(void)
{
QRinput *stream;
char num[17]="0123456789012345";
int bits;
testStart("Estimation of Numeric stream (16 digits)");
stream = QRinput_new();
QRinput_append(stream, QR_MODE_NUM, 16, (unsigned char *)num);
bits = QRinput_estimateBitStreamSize(stream, 0);
testEndExp(bits == 68);
QRinput_append(gstream, QR_MODE_NUM, 16, (unsigned char *)num);
QRinput_free(stream);
}
static void test_numbit3(void)
{
QRinput *stream;
char *num;
int bits;
testStart("Estimation of Numeric stream (400 digits)");
stream = QRinput_new();
num = (char *)malloc(401);
memset(num, '1', 400);
num[400] = '\0';
QRinput_append(stream, QR_MODE_NUM, 400, (unsigned char *)num);
bits = QRinput_estimateBitStreamSize(stream, 0);
/* 4 + 10 + 133*10 + 4 = 1348 */
testEndExp(bits == 1348);
QRinput_append(gstream, QR_MODE_NUM, 400, (unsigned char *)num);
QRinput_free(stream);
free(num);
}
static void test_an(void)
{
QRinput *stream;
char str[6]="AC-42";
int bits;
testStart("Estimation of Alphabet-Numeric stream (5 chars)");
stream = QRinput_new();
QRinput_append(stream, QR_MODE_AN, 5, (unsigned char *)str);
bits = QRinput_estimateBitStreamSize(stream, 0);
testEndExp(bits == 41);
QRinput_append(gstream, QR_MODE_AN, 5, (unsigned char *)str);
QRinput_free(stream);
}
static void test_8(void)
{
QRinput *stream;
char str[9]="12345678";
int bits;
testStart("Estimation of 8 bit data stream (8 bytes)");
stream = QRinput_new();
QRinput_append(stream, QR_MODE_8, 8, (unsigned char *)str);
bits = QRinput_estimateBitStreamSize(stream, 0);
testEndExp(bits == 76);
QRinput_append(gstream, QR_MODE_8, 8, (unsigned char *)str);
QRinput_free(stream);
}
static void test_structure(void)
{
QRinput *stream;
int bits;
testStart("Estimation of a structure-append header");
stream = QRinput_new();
QRinput_insertStructuredAppendHeader(stream, 10, 1, 0);
bits = QRinput_estimateBitStreamSize(stream, 1);
testEndExp(bits == 20);
QRinput_insertStructuredAppendHeader(gstream, 10, 1, 0);
QRinput_free(stream);
}
static void test_kanji(void)
{
int res;
QRinput *stream;
unsigned char str[4]= {0x93, 0x5f,0xe4, 0xaa};
int bits;
testStart("Estimation of Kanji stream (2 chars)");
stream = QRinput_new();
res = QRinput_append(stream, QR_MODE_KANJI, 4, (unsigned char *)str);
if(res < 0) {
printf("Failed to add.\n");
testEnd(1);
} else {
bits = QRinput_estimateBitStreamSize(stream, 0);
testEndExp(bits == 38);
QRinput_append(gstream, QR_MODE_KANJI, 4, (unsigned char *)str);
}
QRinput_free(stream);
}
static void test_mix(void)
{
int bits;
testStart("Estimation of Mixed stream");
bits = QRinput_estimateBitStreamSize(gstream, 0);
testEndExp(bits == (41 + 68 + 1348 + 41 + 76 + 38 + 20));
QRinput_free(gstream);
}
/* Taken from JISX 0510:2018, p.23 */
static void test_numbit1_mqr(void)
{
QRinput *stream;
char *str = "0123456789012345";
int bits;
testStart("Estimation of Numeric stream for Micro QR Code (16 digits)");
stream = QRinput_newMQR(3, QR_ECLEVEL_M);
QRinput_append(stream, QR_MODE_NUM, 16, (const unsigned char *)str);
bits = QRinput_estimateBitStreamSize(stream, QRinput_getVersion(stream));
assert_equal(bits, 61, "Estimated bit length is wrong: %d, expected: %d.\n", bits, 61);
QRinput_free(stream);
stream = QRinput_newMQR(4, QR_ECLEVEL_M);
QRinput_append(stream, QR_MODE_NUM, 16, (const unsigned char *)str);
bits = QRinput_estimateBitStreamSize(stream, QRinput_getVersion(stream));
assert_equal(bits, 63, "Estimated bit length is wrong: %d, expected: %d.\n", bits, 63);
QRinput_free(stream);
testFinish();
}
int main()
{
gstream = QRinput_new();
int tests = 9;
testInit(tests);
test_numbit();
test_numbit2();
test_numbit3();
test_an();
test_8();
test_kanji();
test_structure();
test_mix();
test_numbit1_mqr();
testReport(tests);
return 0;
}
@@ -0,0 +1,411 @@
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "../mask.h"
#include "../qrspec.h"
#include "decoder.h"
static char dot[2] = {'_', '#'};
static char *maskPatterns[8] = {
/* (i + j) mod 2 = 0 */
"#_#_#_"
"_#_#_#"
"#_#_#_"
"_#_#_#"
"#_#_#_"
"_#_#_#",
/* i mod 2 = 0 */
"######"
"______"
"######"
"______"
"######"
"______",
/* j mod 3 = 0 */
"#__#__"
"#__#__"
"#__#__"
"#__#__"
"#__#__"
"#__#__",
/* (i + j) mod 3 = 0 */
"#__#__"
"__#__#"
"_#__#_"
"#__#__"
"__#__#"
"_#__#_",
/* ((i div 2) + (j div 3)) mod 2 = 0 */
"###___"
"###___"
"___###"
"___###"
"###___"
"###___",
/* (ij) mod 2 + (ij) mod 3 = 0 */
"######"
"#_____"
"#__#__"
"#_#_#_"
"#__#__"
"#_____",
/* ((ij) mod 2 + (ij) mod 3) mod 2 = 0 */
"######"
"###___"
"##_##_"
"#_#_#_"
"#_##_#"
"#___##",
/* ((ij) mod 3 + (i+j) mod 2) mod 2 = 0 */
"#_#_#_"
"___###"
"#___##"
"_#_#_#"
"###___"
"_###__"
};
static void print_mask(int mask)
{
const unsigned int w = 6;
unsigned char frame[w * w], *masked, *p;
int x, y;
memset(frame, 0, w * w);
masked = Mask_makeMaskedFrame(w, frame, mask);
p = masked;
for(y=0; y<w; y++) {
for(x=0; x<w; x++) {
putchar(dot[*p&1]);
p++;
}
printf("\n");
}
printf("\n");
free(masked);
}
static void print_masks(void)
{
int i;
puts("\nPrinting mask patterns.");
for(i=0; i<8; i++) {
print_mask(i);
}
}
static int test_mask(int mask)
{
const int w = 6;
unsigned char frame[w * w], *masked, *p;
char *q;
int x, y;
int err = 0;
memset(frame, 0, w * w);
masked = Mask_makeMaskedFrame(w, frame, mask);
p = masked;
q = maskPatterns[mask];
for(y=0; y<w; y++) {
for(x=0; x<w; x++) {
if(dot[*p&1] != *q) {
err++;
}
p++;
q++;
}
}
free(masked);
return err;
}
static void test_masks(void)
{
int i;
testStart("Mask pattern checks");
for(i=0; i<8; i++) {
assert_zero(test_mask(i), "Mask pattern %d incorrect.\n", i);
}
testFinish();
}
#define N1 (3)
#define N2 (3)
#define N3 (40)
#define N4 (10)
static void test_eval(void)
{
unsigned char *frame;
unsigned int w = 6;
int demerit;
frame = (unsigned char *)malloc(w * w);
testStart("Test mask evaluation (all white)");
memset(frame, 0, w * w);
demerit = Mask_evaluateSymbol(w, frame);
testEndExp(demerit == ((N1 + 1)*w*2 + N2 * (w - 1) * (w - 1)));
testStart("Test mask evaluation (all black)");
memset(frame, 1, w * w);
demerit = Mask_evaluateSymbol(w, frame);
testEndExp(demerit == ((N1 + 1)*w*2 + N2 * (w - 1) * (w - 1)));
free(frame);
}
/* .#.#.#.#.#
* #.#.#.#.#.
* ..##..##..
* ##..##..##
* ...###...#
* ###...###.
* ....####..
* ####....##
* .....#####
* #####.....
*/
static void test_eval2(void)
{
unsigned char *frame;
unsigned int w = 10;
int demerit;
unsigned int x;
frame = (unsigned char *)malloc(w * w);
testStart("Test mask evaluation (run length penalty check)");
for(x=0; x<w; x++) {
frame[ x] = x & 1;
frame[w + x] = (x & 1) ^ 1;
frame[w*2 + x] = (x / 2) & 1;
frame[w*3 + x] = ((x / 2) & 1) ^ 1;
frame[w*4 + x] = (x / 3) & 1;
frame[w*5 + x] = ((x / 3) & 1) ^ 1;
frame[w*6 + x] = (x / 4) & 1;
frame[w*7 + x] = ((x / 4) & 1) ^ 1;
frame[w*8 + x] = (x / 5) & 1;
frame[w*9 + x] = ((x / 5) & 1) ^ 1;
}
demerit = Mask_evaluateSymbol(w, frame);
testEndExp(demerit == N1 * 4 + N2 * 4);
free(frame);
}
static void test_calcN2(void)
{
unsigned char frame[64];
int width;
int demerit;
int x, y;
testStart("Test mask evaluation (2x2 block check)");
width = 4;
for(y = 0; y < width; y++) {
for(x = 0; x < width; x++) {
frame[y * width + x] = ((x & 2) ^ (y & 2)) >> 1;
}
}
demerit = Mask_calcN2(width, frame);
assert_equal(demerit, N2 * 4, "Calculation of N2 demerit is wrong: %d, expected %d", demerit, N2 * 4);
width = 4;
for(y = 0; y < width; y++) {
for(x = 0; x < width; x++) {
frame[y * width + x] = (((x + 1) & 2) ^ (y & 2)) >> 1;
}
}
demerit = Mask_calcN2(width, frame);
assert_equal(demerit, N2 * 2, "Calculation of N2 demerit is wrong: %d, expected %d", demerit, N2 * 2);
width = 6;
for(y = 0; y < width; y++) {
for(x = 0; x < width; x++) {
frame[y * width + x] = (x / 3) ^ (y / 3);
}
}
demerit = Mask_calcN2(width, frame);
assert_equal(demerit, N2 * 16, "Calculation of N2 demerit is wrong: %d, expected %d", demerit, N2 * 16);
testFinish();
}
static void test_eval3(void)
{
unsigned char *frame;
int w = 15;
int demerit;
int x, y;
static unsigned char pattern[7][15] = {
{0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0}, // N3x1
{1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1}, // N3x1
{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1}, // N3x1
{1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0}, // 0
{1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1}, // N3x2
{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0}, // N3 + (N1+1)
{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1} // (N1+1)
};
frame = (unsigned char *)malloc(w * w);
testStart("Test mask evaluation (1:1:3:1:1 check)");
for(y=0; y<5; y++) {
for(x=0; x<w; x++) {
frame[w*y*2 + x] = pattern[y][x];
frame[w*(y*2+1) + x] = pattern[y][x]^1;
}
}
for(x=0; x<w; x++) {
frame[w*10 + x] = x & 1;
}
for(y=5; y<7; y++) {
for(x=0; x<w; x++) {
frame[w*(y*2+1) + x] = pattern[y][x];
frame[w*(y*2+2) + x] = pattern[y][x]^1;
}
}
/*
for(y=0; y<w; y++) {
for(x=0; x<w; x++) {
printf("%s", frame[w*y+x]?"##":"..");
}
printf("\n");
}
*/
demerit = Mask_evaluateSymbol(w, frame);
testEndExp(demerit == N3 * 10 + (N1 + 1) * 4);
free(frame);
}
static void test_format(void)
{
unsigned char *frame, *masked;
int version, mask, width, dmask;
QRecLevel level, dlevel;
QRcode *code;
int ret;
testStart("Checking format info.");
for(version=1; version<=QRSPEC_VERSION_MAX; version++) {
frame = QRspec_newFrame(version);
width = QRspec_getWidth(version);
for(level=QR_ECLEVEL_L; level<=QR_ECLEVEL_H; level++) {
for(mask=0; mask<8; mask++) {
masked = Mask_makeMask(width, frame, mask, level);
code = QRcode_new(version, width, masked);
ret = QRcode_decodeFormat(code, &dlevel, &dmask);
assert_zero(ret, "Something wrong in format info.\n");
assert_equal(dlevel, level, "Decoded level is wrong: %d, expected %d", dlevel, level);
assert_equal(dmask, mask, "Decoded mask is wrong: %d, expected %d", dlevel, level);
QRcode_free(code);
}
}
free(frame);
}
testFinish();
}
static void test_calcRunLength(void)
{
int width = 5;
unsigned char frame[width * width];
int runLength[width + 1];
int i, j;
int length;
static unsigned char pattern[6][5] = {
{0, 1, 0, 1, 0},
{1, 0, 1, 0, 1},
{0, 0, 0, 0, 0},
{1, 1, 1, 1, 1},
{0, 0, 1, 1, 1},
{1, 1, 0, 0, 0}
};
static int expected[6][7] = {
{ 1, 1, 1, 1, 1, 0, 5},
{-1, 1, 1, 1, 1, 1, 6},
{ 5, 0, 0, 0, 0, 0, 1},
{-1, 5, 0, 0, 0, 0, 2},
{ 2, 3, 0, 0, 0, 0, 2},
{-1, 2, 3, 0, 0, 0, 3}
};
testStart("Test runlength calc function");
for(i=0; i<6; i++) {
length = Mask_calcRunLengthH(width, pattern[i], runLength);
assert_equal(expected[i][6], length, "Length incorrect: %d, expected %d.\n", length, expected[i][6]);
assert_zero(memcmp(runLength, expected[i], sizeof(int) * expected[i][6]), "Run length does not match: pattern %d, horizontal access.\n", i);
for(j=0; j<width; j++) {
frame[j * width] = pattern[i][j];
}
length = Mask_calcRunLengthV(width, frame, runLength);
assert_equal(expected[i][6], length, "Length incorrect: %d, expected %d.\n", length, expected[i][6]);
assert_zero(memcmp(runLength, expected[i], sizeof(int) * expected[i][6]), "Run length does not match: pattern %d, vertical access.\n", i);
}
testFinish();
}
static void test_calcN1N3(void)
{
int runLength[26];
int length;
int demerit;
int i;
static unsigned char pattern[][16] = {
{1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, N3},
{0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, N3},
{1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0},
{1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, N3},
{1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, N3},
{1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, N3 * 2},
};
static unsigned char pattern2[][19] = {
{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, N3 + N1 + 1},
{0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, N3 + N1 + 1},
{1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, N1 + 1},
{1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, N3 + N1 + 1},
{1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, N3 + N1 + 1}
};
testStart("Test N3 penalty calculation");
for(i=0; i<6; i++) {
length = Mask_calcRunLengthH(15, pattern[i], runLength);
demerit = Mask_calcN1N3(length, runLength);
assert_equal(pattern[i][15], demerit, "N3 penalty is wrong: %d, expected %d\n", demerit, pattern[i][15]);
}
for(i=0; i<5; i++) {
length = Mask_calcRunLengthH(18, pattern2[i], runLength);
demerit = Mask_calcN1N3(length, runLength);
assert_equal(pattern2[i][18], demerit, "N3 penalty is wrong: %d, expected %d\n", demerit, pattern2[i][18]);
}
testFinish();
}
int main(int argc, char **argv)
{
int tests = 9;
testInit(tests);
test_masks();
test_eval();
test_eval2();
test_eval3();
test_format();
test_calcN2();
test_calcRunLength();
test_calcN1N3();
testReport(tests);
if(argc > 1) {
print_masks();
}
return 0;
}
@@ -0,0 +1,155 @@
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "../mmask.h"
#include "../mqrspec.h"
static char dot[2] = {'_', '#'};
static char *maskPatterns[4] = {
/* i mod 2 = 0 */
"######"
"______"
"######"
"______"
"######"
"______",
/* ((i div 2) + (j div 3)) mod 2 = 0 */
"###___"
"###___"
"___###"
"___###"
"###___"
"###___",
/* ((ij) mod 2 + (ij) mod 3) mod 2 = 0 */
"######"
"###___"
"##_##_"
"#_#_#_"
"#_##_#"
"#___##",
/* ((ij) mod 3 + (i+j) mod 2) mod 2 = 0 */
"#_#_#_"
"___###"
"#___##"
"_#_#_#"
"###___"
"_###__"
};
static void print_mask(int mask)
{
const int w = 6;
unsigned char frame[w * w], *masked, *p;
int x, y;
memset(frame, 0, w * w);
masked = MMask_makeMaskedFrame(w, frame, mask);
p = masked;
for(y=0; y<w; y++) {
for(x=0; x<w; x++) {
putchar(dot[*p&1]);
p++;
}
printf("\n");
}
printf("\n");
free(masked);
}
static void print_masks(void)
{
int i;
puts("\nPrinting mask patterns.");
for(i=0; i<4; i++) {
print_mask(i);
}
}
static int test_mask(int mask)
{
const int w = 6;
unsigned char frame[w * w], *masked, *p;
char *q;
int x, y;
int err = 0;
memset(frame, 0, w * w);
masked = MMask_makeMaskedFrame(w, frame, mask);
p = masked;
q = maskPatterns[mask];
for(y=0; y<w; y++) {
for(x=0; x<w; x++) {
if(dot[*p&1] != *q) {
err++;
}
p++;
q++;
}
}
free(masked);
return err;
}
static void test_masks(void)
{
int i;
testStart("Mask pattern checks");
for(i=0; i<4; i++) {
assert_zero(test_mask(i), "Mask pattern %d incorrect.\n", i);
}
testFinish();
}
static void test_maskEvaluation(void)
{
static const int w = 11;
unsigned char pattern[w * w];
int i, score;
memset(pattern, 0, w * w);
testStart("Test mask evaluation");
score = MMask_evaluateSymbol(w, pattern);
assert_equal(score, 0, "Mask score caluculation is incorrect. (score=%d (%d expected)\n", score, 0);
for(i=0; i<w; i++) {
pattern[(w-1) * w + i] = 1;
}
score = MMask_evaluateSymbol(w, pattern);
assert_equal(score, 16 + w - 1, "Mask score caluculation is incorrect. (score=%d) (%d expected)\n", score, 16 + w - 1);
for(i=0; i<w; i++) {
pattern[(w-1) * w + i] = 0;
pattern[i * w + w - 1] = 1;
}
score = MMask_evaluateSymbol(w, pattern);
assert_equal(score, 16 + w - 1, "Mask score caluculation is incorrect. (score=%d) (%d expected)\n", score, 16 + w - 1);
for(i=0; i<w; i++) {
pattern[(w-1) * w + i] = 1;
pattern[i * w + w - 1] = 1;
}
score = MMask_evaluateSymbol(w, pattern);
assert_equal(score, 16 * (w - 1) + w - 1, "Mask score caluculation is incorrect. (score=%d) (%d expected)\n", score, 16 * (w - 1) + w - 1);
testFinish();
}
int main(int argc, char **argv)
{
int tests = 2;
testInit(tests);
test_masks();
test_maskEvaluation();
testReport(tests);
if(argc > 1) {
print_masks();
}
return 0;
}
@@ -0,0 +1,582 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "common.h"
#include "../qrinput.h"
#include "../split.h"
#include "../qrspec.h"
#include "decoder.h"
#define MAX_LENGTH 7091
static unsigned char data[MAX_LENGTH];
static unsigned char check[MAX_LENGTH];
static const char *AN = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
#define drand(__scale__) ((__scale__) * (double)rand() / ((double)RAND_MAX + 1.0))
static int fill8bitString(void)
{
int len, i;
len = 1 + (int)drand((MAX_LENGTH - 2));
for(i=0; i<len; i++) {
data[i] = (unsigned char)drand(255) + 1;
}
data[len] = '\0';
return len;
}
static int fill8bitData(void)
{
int len, i;
len = 1 + (int)drand((MAX_LENGTH - 2));
for(i=0; i<len; i++) {
data[i] = (unsigned char)drand(256);
}
data[len] = '\0';
return len;
}
static int fillANData(void)
{
int len, i;
len = 1 + (int)drand((MAX_LENGTH - 2));
for(i=0; i<len; i++) {
data[i] = AN[(int)drand(45)];
}
data[len] = '\0';
return len;
}
static void test_encode_an(int num)
{
int ret;
int len;
len = fillANData();
QRcode *qrcode;
QRdata *qrdata;
FILE *fp;
char buf[256];
qrcode = QRcode_encodeString((char *)data, 0, num % 4, QR_MODE_8, num % 2);
if(qrcode == NULL) {
if(errno == ERANGE) return;
perror("test_encode_an aborted at QRcode_encodeString():");
printf("Length: %d\n", len);
printf("Level: %d\n", num % 4);
return;
}
qrdata = QRcode_decode(qrcode);
if(qrdata == NULL) {
printf("#%d: Failed to decode this code.\n", num);
QRcode_free(qrcode);
return;
}
if(qrdata->size != len) {
printf("#%d: length mismatched (orig: %d, decoded: %d)\n", num, len, qrdata->size);
}
ret = memcmp(qrdata->data, data, len);
if(ret != 0) {
unsigned char *frame, *p;
unsigned int x;
int y,c;
int dataLength, eccLength;
QRinput *input;
QRcode *origcode;
BitStream *bstream;
int spec[5];
printf("#%d: data mismatched.\n", num);
printf("Version: %d\n", qrcode->version);
QRspec_getEccSpec(qrcode->version, num%4, spec);
printf("DataLength: %d\n", QRspec_rsDataLength(spec));
printf("BlockNum1: %d\n", QRspec_rsBlockNum1(spec));
printf("BlockNum: %d\n", QRspec_rsBlockNum(spec));
printf("DataCodes1: %d\n", QRspec_rsDataCodes1(spec));
snprintf(buf, 256, "monkey-orig-%d.dat", num);
fp = fopen(buf, "w");
fputs((char *)data, fp);
fclose(fp);
snprintf(buf, 256, "monkey-result-%d.dat", num);
fp = fopen(buf, "w");
fputs((char *)qrdata->data, fp);
fclose(fp);
snprintf(buf, 256, "monkey-result-unmasked-%d.dat", num);
fp = fopen(buf, "w");
frame = QRcode_unmask(qrcode);
p = frame;
for(y=0; y<qrcode->width; y++) {
for(x=0; x<qrcode->width; x++) {
fputc((*p&1)?'1':'0', fp);
p++;
}
fputc('\n', fp);
}
fclose(fp);
free(frame);
snprintf(buf, 256, "monkey-orig-unmasked-%d.dat", num);
fp = fopen(buf, "w");
input = QRinput_new2(0, num % 4);
Split_splitStringToQRinput((char *)data, input, QR_MODE_8, num % 2);
origcode = QRcode_encodeMask(input, -2);
p = origcode->data;
for(y=0; y<origcode->width; y++) {
for(x=0; x<origcode->width; x++) {
fputc((*p&1)?'1':'0', fp);
p++;
}
fputc('\n', fp);
}
fclose(fp);
QRcode_free(origcode);
snprintf(buf, 256, "monkey-orig-bits-%d.dat", num);
fp = fopen(buf, "w");
bstream = BitStream_new();
QRinput_mergeBitStream(input, bstream);
c = 0;
for(x=0; x<bstream->length; x++) {
fputc((bstream->data[x]&1)?'1':'0', fp);
if((x & 7) == 7) {
fputc(' ', fp);
c++;
}
if((x & 63) == 63) {
fprintf(fp, "%d\n", c);
}
}
fclose(fp);
QRinput_free(input);
BitStream_free(bstream);
snprintf(buf, 256, "monkey-result-bits-%d.dat", num);
fp = fopen(buf, "w");
bstream = QRcode_extractBits(qrcode, &dataLength, &eccLength);
y = bstream->length;
p = bstream->data;
c = 0;
for(x=0; x<y; x++) {
fputc((p[x]&1)?'1':'0', fp);
if((x & 7) == 7) {
fputc(' ', fp);
c++;
}
if((x & 63) == 63) {
fprintf(fp, "%d\n", c);
}
}
fclose(fp);
BitStream_free(bstream);
}
QRdata_free(qrdata);
QRcode_free(qrcode);
}
static void monkey_encode_an(int loop)
{
int i;
testStart("Monkey test: QRcode_encodeString() - AlphaNumeric string.");
srand(0);
for(i=0; i<loop; i++) {
test_encode_an(i);
}
testEnd(0);
}
static void test_split_an(int num)
{
QRinput *input;
QRinput_List *list;
int len, i, ret;
len = fillANData();
input = QRinput_new2(0, QR_ECLEVEL_L);
if(input == NULL) {
perror("test_split_an aborted at QRinput_new2():");
return;
}
ret = Split_splitStringToQRinput((char *)data, input, QR_MODE_8, 1);
if(ret < 0) {
perror("test_split_an aborted at Split_splitStringToQRinput():");
QRinput_free(input);
return;
}
list = input->head;
i = 0;
while(list != NULL) {
memcpy(check + i, list->data, list->size);
i += list->size;
list = list->next;
}
if(i != len) {
printf("#%d: length is not correct. (%d should be %d)\n", num, i, len);
}
check[i] = '\0';
ret = memcmp(data, check, len);
if(ret != 0) {
printf("#%d: data mismatched.\n", num);
list = input->head;
i = 0;
while(list != NULL) {
ret = memcmp(data + i, list->data, list->size);
printf("wrong chunk:\n");
printf(" position: %d\n", i);
printf(" mode : %d\n", list->mode);
printf(" size : %d\n", list->size);
printf(" data : %.*s\n", list->size, list->data);
i += list->size;
list = list->next;
}
exit(1);
}
QRinput_free(input);
}
static void monkey_split_an(int loop)
{
int i;
testStart("Monkey test: Split_splitStringToQRinput() - AlphaNumeric string.");
srand(0);
for(i=0; i<loop; i++) {
test_split_an(i);
}
testEnd(0);
}
static void test_encode_8(int num)
{
QRcode *qrcode;
QRdata *qrdata;
int len, ret;
len = fill8bitData();
qrcode = QRcode_encodeData(len, data, 0, num % 4);
if(qrcode == NULL) {
if(errno == ERANGE) return;
perror("test_encdoe_8 aborted at QRcode_encodeData():");
return;
}
qrdata = QRcode_decode(qrcode);
if(qrdata == NULL) {
printf("#%d: Failed to decode this code.\n", num);
QRcode_free(qrcode);
return;
}
if(qrdata->size != len) {
printf("#%d: length mismatched (orig: %d, decoded: %d)\n", num, len, qrdata->size);
}
ret = memcmp(qrdata->data, data, len);
if(ret != 0) {
printf("#%d: data mismatched.\n", num);
}
QRdata_free(qrdata);
QRcode_free(qrcode);
}
static void monkey_encode_8(int loop)
{
int i;
testStart("Monkey test: QRcode_encodeData() - 8bit char string.");
srand(0);
for(i=0; i<loop; i++) {
test_encode_8(i);
}
testEnd(0);
}
static void test_split_8(int num)
{
QRinput *input;
QRinput_List *list;
int len, i, ret;
len = fill8bitString();
input = QRinput_new2(0, QR_ECLEVEL_L);
if(input == NULL) {
perror("test_split_8 aborted at QRinput_new2():");
return;
}
ret = Split_splitStringToQRinput((char *)data, input, QR_MODE_8, 1);
if(ret < 0) {
perror("test_split_8 aborted at Split_splitStringToQRinput():");
QRinput_free(input);
return;
}
list = input->head;
i = 0;
while(list != NULL) {
memcpy(check + i, list->data, list->size);
i += list->size;
list = list->next;
}
if(i != len) {
printf("#%d: length is not correct. (%d should be %d)\n", num, i, len);
}
check[i] = '\0';
ret = memcmp(data, check, len);
if(ret != 0) {
printf("#%d: data mismatched.\n", num);
list = input->head;
i = 0;
while(list != NULL) {
ret = memcmp(data + i, list->data, list->size);
printf("wrong chunk:\n");
printf(" position: %d\n", i);
printf(" mode : %d\n", list->mode);
printf(" size : %d\n", list->size);
printf(" data : %.*s\n", list->size, list->data);
i += list->size;
list = list->next;
}
exit(1);
}
QRinput_free(input);
}
static void monkey_split_8(int loop)
{
int i;
testStart("Monkey test: Split_splitStringToQRinput() - 8bit char string.");
srand(0);
for(i=0; i<loop; i++) {
test_split_8(i);
}
testEnd(0);
}
static void test_encode_kanji(int num)
{
QRcode *qrcode;
QRdata *qrdata;
int len, ret;
len = fill8bitString();
qrcode = QRcode_encodeString((char *)data, 0, num % 4, QR_MODE_8, 1);
if(qrcode == NULL) {
if(errno == ERANGE) return;
perror("test_encdoe_kanji aborted at QRcode_encodeString():");
return;
}
qrdata = QRcode_decode(qrcode);
if(qrdata == NULL) {
printf("#%d: Failed to decode this code.\n", num);
QRcode_free(qrcode);
return;
}
if(qrdata->size != len) {
printf("#%d: length mismatched (orig: %d, decoded: %d)\n", num, len, qrdata->size);
}
ret = memcmp(qrdata->data, data, len);
if(ret != 0) {
printf("#%d: data mismatched.\n", num);
}
QRdata_free(qrdata);
QRcode_free(qrcode);
}
static void monkey_encode_kanji(int loop)
{
int i;
testStart("Monkey test: QRcode_encodeString() - kanji string.");
srand(0);
for(i=0; i<loop; i++) {
test_encode_kanji(i);
}
testEnd(0);
}
static void test_split_kanji(int num)
{
QRinput *input;
QRinput_List *list;
int len, i, ret;
len = fill8bitString();
input = QRinput_new2(0, QR_ECLEVEL_L);
if(input == NULL) {
perror("test_split_kanji aborted at QRinput_new2():");
return;
}
ret = Split_splitStringToQRinput((char *)data, input, QR_MODE_KANJI, 1);
if(ret < 0) {
perror("test_split_kanji aborted at Split_splitStringToQRinput():");
QRinput_free(input);
return;
}
list = input->head;
i = 0;
while(list != NULL) {
memcpy(check + i, list->data, list->size);
i += list->size;
list = list->next;
}
if(i != len) {
printf("#%d: length is not correct. (%d should be %d)\n", num, i, len);
}
check[i] = '\0';
ret = memcmp(data, check, len);
if(ret != 0) {
printf("#%d: data mismatched.\n", num);
list = input->head;
i = 0;
while(list != NULL) {
ret = memcmp(data + i, list->data, list->size);
printf("wrong chunk:\n");
printf(" position: %d\n", i);
printf(" mode : %d\n", list->mode);
printf(" size : %d\n", list->size);
printf(" data : %.*s\n", list->size, list->data);
i += list->size;
list = list->next;
}
exit(1);
}
QRinput_free(input);
}
static void monkey_split_kanji(int loop)
{
int i;
testStart("Monkey test: Split_splitStringToQRinput() - kanji string.");
srand(0);
for(i=0; i<loop; i++) {
test_split_kanji(i);
}
testEnd(0);
}
static void test_split_structure(int num)
{
QRinput *input;
QRinput_Struct *s;
QRcode_List *codes, *list;
QRinput_InputList *il;
int version;
QRecLevel level;
int c, i, ret;
version = (int)drand(40) + 1;
level = (QRecLevel)drand(4);
fill8bitString();
input = QRinput_new2(version, level);
if(input == NULL) {
perror("test_split_structure aborted at QRinput_new2():");
return;
}
ret = Split_splitStringToQRinput((char *)data, input, QR_MODE_KANJI, 1);
if(ret < 0) {
perror("test_split_structure aborted at Split_splitStringToQRinput():");
QRinput_free(input);
return;
}
s = QRinput_splitQRinputToStruct(input);
if(s == NULL) {
if(errno != 0 && errno != ERANGE) {
perror("test_split_structure aborted at QRinput_splitQRinputToStruct():");
}
QRinput_free(input);
return;
}
il = s->head;
i = 0;
while(il != NULL) {
if(il->input->version != version) {
printf("Test: version %d, level %c\n", version, levelChar[level]);
printf("wrong version number.\n");
printQRinputInfo(il->input);
exit(1);
}
i++;
il = il->next;
}
codes = QRcode_encodeInputStructured(s);
if(codes == NULL) {
perror("test_split_structure aborted at QRcode_encodeInputStructured():");
QRinput_free(input);
QRinput_Struct_free(s);
return;
}
list = codes;
il = s->head;
c = 0;
while(list != NULL) {
if(list->code->version != version) {
printf("#%d: data mismatched.\n", num);
printf("Test: version %d, level %c\n", version, levelChar[level]);
printf("code #%d\n", c);
printf("Version mismatch: %d should be %d\n", list->code->version, version);
printf("max bits: %d\n", QRspec_getDataLength(version, level) * 8 - 20);
printQRinputInfo(il->input);
printQRinput(input);
exit(1);
}
list = list->next;
il = il->next;
c++;
}
QRinput_free(input);
QRinput_Struct_free(s);
QRcode_List_free(codes);
return;
}
static void monkey_split_structure(int loop)
{
int i;
testStart("Monkey test: QRinput_splitQRinputToStruct.");
srand(0);
for(i=0; i<loop; i++) {
test_split_structure(i);
}
testEnd(0);
}
int main(int argc, char **argv)
{
int loop = 1000;
if(argc == 2) {
loop = atoi(argv[1]);
}
int tests = 7;
testInit(tests);
monkey_split_an(loop);
monkey_encode_an(loop);
monkey_split_8(loop);
monkey_encode_8(loop);
monkey_split_kanji(loop);
monkey_encode_kanji(loop);
monkey_split_structure(loop);
testReport(tests);
return 0;
}
@@ -0,0 +1,181 @@
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "../mqrspec.h"
static unsigned char v4frame[] = {
0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc0,0x91,0x90,0x91,0x90,0x91,0x90,0x91,0x90,0x91,
0xc1,0xc0,0xc0,0xc0,0xc0,0xc0,0xc1,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xc1,0xc0,0xc1,0xc1,0xc1,0xc0,0xc1,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xc1,0xc0,0xc1,0xc1,0xc1,0xc0,0xc1,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xc1,0xc0,0xc1,0xc1,0xc1,0xc0,0xc1,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xc1,0xc0,0xc0,0xc0,0xc0,0xc0,0xc1,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x91,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
static void test_newFrame(void)
{
int width, i, y;
unsigned char *frame;
testStart("Test empty frames");
for(i=1; i<MQRSPEC_VERSION_MAX; i++) {
frame = MQRspec_newFrame(i);
width = MQRspec_getWidth(i);
for(y=0; y<width; y++) {
assert_zero(memcmp(&frame[y * width], &v4frame[y * MQRSPEC_WIDTH_MAX], width), "Mismatch found in version %d, line %d.\n", i, y);
}
free(frame);
}
testFinish();
}
static void test_newframe_invalid(void)
{
unsigned char *frame;
testStart("Checking MQRspec_newFrame with invalid version.");
frame = MQRspec_newFrame(0);
assert_null(frame, "MQRspec_newFrame(0) returns non-NULL.");
frame = MQRspec_newFrame(MQRSPEC_VERSION_MAX+1);
assert_null(frame, "MQRspec_newFrame(0) returns non-NULL.");
testFinish();
}
/* See Table 10 (pp.115) of Appendix 1, JIS X0510:2004 */
static unsigned int calcFormatInfo(int type, int mask)
{
unsigned int data, ecc, b, code;
int i, c;
data = (type << 12) | (mask << 10);
ecc = data;
b = 1 << 14;
for(i=0; b != 0; i++) {
if(ecc & b) break;
b = b >> 1;
}
c = 4 - i;
code = 0x537 << c ; //10100110111
b = 1 << (10 + c);
for(i=0; i<=c; i++) {
if(b & ecc) {
ecc ^= code;
}
code = code >> 1;
b = b >> 1;
}
return (data | ecc) ^ 0x4445;
}
/* See Table 10 of Appendix 1. (pp.115) */
static const int typeTable[4][3] = {
{ 0, -1, -1},
{ 1, 2, -1},
{ 3, 4, -1},
{ 5, 6, 7}
};
static void test_format(void)
{
unsigned int format;
int version, l, mask;
int type;
int err = 0;
testStart("Format info test");
for(version=1; version<=MQRSPEC_VERSION_MAX; version++) {
for(l=QR_ECLEVEL_L; l<=QR_ECLEVEL_Q; l++) {
for(mask=0; mask<4; mask++) {
format = MQRspec_getFormatInfo(mask, version, (QRecLevel)l);
type = typeTable[version - 1][l];
if(type == -1) {
if(format != 0) {
printf("Error in version %d, level %d, mask %d\n",
version, l, mask);
err++;
}
} else {
if(format != calcFormatInfo(type, mask)) {
printf("Error in version %d, level %d, mask %d\n",
version, l, mask);
err++;
}
}
}
}
}
testEnd(err);
}
static void print_format(void)
{
unsigned int format;
int i, j;
puts("\nPrinting hex strings of format information.");
for(i=0; i<4; i++) {
for(j=0; j<8; j++) {
format = calcFormatInfo(j, i);
printf("0x%04x, ", format);
}
printf("\n");
}
}
/**
* See Table 7 of Appendix 1.
*/
static int datalen[4][3] = {
{ 20, 0, 0},
{ 40, 32, 0},
{ 84, 68, 0},
{128, 112, 80},
};
static void test_dataLength(void)
{
int v, l;
int bits;
int err = 0;
testStart("Test dataLength");
for(v=0; v<4; v++) {
for(l=0; l<3; l++) {
bits = MQRspec_getDataLengthBit(v+1, (QRecLevel)l);
if(bits != datalen[v][l]) {
printf("Error in version %d, level %d.\n", v, l);
err++;
}
}
}
testEnd(err);
}
int main(int argc, char **argv)
{
int tests = 4;
testInit(tests);
test_newFrame();
test_newframe_invalid();
test_format();
test_dataLength();
testReport(tests);
if(argc > 1) {
print_format();
}
return 0;
}
+48
View File
@@ -0,0 +1,48 @@
#!/bin/sh
COMMAND=../qrencode
TARGET_DIR="test_images"
VALGRIND_COMMAND="libtool --mode=execute valgrind"
VALGRIND_OPTIONS="--leak-check=full --show-reachable=yes"
if [ "x$1" = 'xvalgrind' ]; then
COMMAND="$VALGRIND_COMMAND $VALGRIND_OPTIONS $COMMAND"
fi
repeatchar()
{
printf %${2}s | tr ' ' ${1}
}
test_command_success()
{
repeatchar ${1} ${2} | $COMMAND -o - -l L ${3} > /dev/null
if [ $? -ne 0 ]; then
echo "Failed to encode $fn.txt"
exit 1
fi
}
test_command_fail()
{
repeatchar ${1} ${2} | $COMMAND -o - -l L ${3} > /dev/null
if [ $? -eq 0 ]; then
echo "Unexpectedly successed to encode '${1}'x'${2}' with '${3}'."
exit 1
else
echo "^^^this is the expected error. Everything OK."
fi
}
mkdir -p $TARGET_DIR
test_command_success '1' 7089
test_command_success 'A' 4296
test_command_success 'a' 2953
test_command_success '\211' 3634 '-k'
test_command_fail '1' 7090
test_command_fail 'A' 4297
test_command_fail 'a' 2954
test_command_fail '\211' 3636 '-k'
test_command_fail '1' 15000
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,319 @@
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "../qrspec.h"
#include "../qrencode_inner.h"
#include "decoder.h"
#ifndef SRCDIR
# define SRCDIR
#endif
static void print_eccTable(void)
{
int i, j;
int ecc;
int data;
int spec[5];
puts("\nPrinting ECC table.\n");
for(i=1; i<=QRSPEC_VERSION_MAX; i++) {
printf("Version %2d\n", i);
for(j=0; j<4; j++) {
QRspec_getEccSpec(i, (QRecLevel)j, spec);
data = QRspec_rsBlockNum1(spec) * QRspec_rsDataCodes1(spec)
+ QRspec_rsBlockNum2(spec) * QRspec_rsDataCodes2(spec);
ecc = QRspec_rsBlockNum1(spec) * QRspec_rsEccCodes1(spec)
+ QRspec_rsBlockNum2(spec) * QRspec_rsEccCodes2(spec);
printf("%3d\t", data);
printf("%3d\t", ecc);
printf("%2d\t", QRspec_rsBlockNum1(spec));
printf("(%3d, %3d, %3d)\n",
QRspec_rsDataCodes1(spec) + QRspec_rsEccCodes1(spec),
QRspec_rsDataCodes1(spec),
QRspec_rsEccCodes1(spec));
if(QRspec_rsBlockNum2(spec) > 0) {
printf("\t%2d\t", QRspec_rsBlockNum2(spec));
printf("(%3d, %3d, %3d)\n",
QRspec_rsDataCodes2(spec) + QRspec_rsEccCodes2(spec),
QRspec_rsDataCodes2(spec),
QRspec_rsEccCodes2(spec));
}
}
}
}
static void test_eccTable(void)
{
int i, j;
int ecc;
int data;
int err = 0;
int spec[5];
testStart("Checking ECC table.");
for(i=1; i<=QRSPEC_VERSION_MAX; i++) {
for(j=0; j<4; j++) {
QRspec_getEccSpec(i, (QRecLevel)j, spec);
data = QRspec_rsBlockNum1(spec) * QRspec_rsDataCodes1(spec)
+ QRspec_rsBlockNum2(spec) * QRspec_rsDataCodes2(spec);
ecc = QRspec_rsBlockNum1(spec) * QRspec_rsEccCodes1(spec)
+ QRspec_rsBlockNum2(spec) * QRspec_rsEccCodes2(spec);
if(data + ecc != QRspec_getDataLength(i, (QRecLevel)j) + QRspec_getECCLength(i, (QRecLevel)j)) {
printf("Error in version %d, level %d: invalid size\n", i, j);
printf("%d %d %d %d %d %d\n", spec[0], spec[1], spec[2], spec[3], spec[4], spec[2]);
err++;
}
if(ecc != QRspec_getECCLength(i, (QRecLevel)j)) {
printf("Error in version %d, level %d: invalid data\n", i, j);
printf("%d %d %d %d %d %d\n", spec[0], spec[1], spec[2], spec[3], spec[4], spec[2]);
err++;
}
}
}
testEnd(err);
}
static void test_eccTable2(void)
{
int i;
int spec[5];
const int correct[7][6] = {
{ 8, 1, 0, 2, 60, 38},
{ 8, 1, 1, 2, 61, 39},
{24, 2, 0, 11, 54, 24},
{24, 2, 1, 16, 55, 25},
{32, 0, 0, 17, 145, 115},
{40, 3, 0, 20, 45, 15},
{40, 3, 1, 61, 46, 16},
};
testStart("Checking ECC table(2)");
for(i=0; i<7; i++) {
QRspec_getEccSpec(correct[i][0], (QRecLevel)correct[i][1], spec);
if(correct[i][2] == 0) {
assert_equal(QRspec_rsBlockNum1(spec), correct[i][3],
"Error in version %d, level %d. rsBlockNum1 was %d, expected %d.\n",
correct[i][0], correct[i][1],
QRspec_rsBlockNum1(spec), correct[i][3]);
assert_equal(QRspec_rsDataCodes1(spec) + QRspec_rsEccCodes1(spec), correct[i][4],
"Error in version %d, level %d. rsDataCodes1 + rsEccCodes1 was %d, expected %d.\n",
correct[i][0], correct[i][1],
QRspec_rsDataCodes1(spec) + QRspec_rsEccCodes1(spec), correct[i][4]);
assert_equal(QRspec_rsDataCodes1(spec), correct[i][5],
"Error in version %d, level %d. rsDataCodes1 was %d, expected %d.\n",
correct[i][0], correct[i][1],
QRspec_rsDataCodes1(spec), correct[i][5]);
} else {
assert_equal(QRspec_rsBlockNum2(spec), correct[i][3],
"Error in version %d, level %d. rsBlockNum2 was %d, expected %d.\n",
correct[i][0], correct[i][1],
QRspec_rsBlockNum2(spec), correct[i][3]);
assert_equal(QRspec_rsDataCodes2(spec) + QRspec_rsEccCodes2(spec), correct[i][4],
"Error in version %d, level %d. rsDataCodes2 + rsEccCodes2 was %d, expected %d.\n",
correct[i][0], correct[i][1],
QRspec_rsDataCodes2(spec) + QRspec_rsEccCodes2(spec), correct[i][4]);
assert_equal(QRspec_rsDataCodes2(spec), correct[i][5],
"Error in version %d, level %d. rsDataCodes2 was %d, expected %d.\n",
correct[i][0], correct[i][1],
QRspec_rsDataCodes2(spec), correct[i][5]);
}
}
testFinish();
}
static void test_newframe(void)
{
unsigned char buf[QRSPEC_WIDTH_MAX * QRSPEC_WIDTH_MAX];
int i, width;
size_t len;
FILE *fp;
unsigned char *frame;
QRcode *qrcode;
int version;
testStart("Checking newly created frame.");
fp = fopen(SRCDIR "frame", "rb");
if(fp == NULL) {
perror("Failed to open \"" SRCDIR "frame\":");
abort();
}
for(i=1; i<=QRSPEC_VERSION_MAX; i++) {
frame = QRspec_newFrame(i);
width = QRspec_getWidth(i);
len = fread(buf, 1, width * width, fp);
if((int)len != width * width) {
perror("Failed to read the pattern file:");
abort();
}
assert_zero(memcmp(frame, buf, len), "frame pattern mismatch (version %d)\n", i);
qrcode = QRcode_new(i, width, frame);
version = QRcode_decodeVersion(qrcode);
assert_equal(version, i, "Decoded version number is wrong: %d, expected %d.\n", version, i);
QRcode_free(qrcode);
}
testFinish();
fclose(fp);
}
static void test_newframe_invalid(void)
{
unsigned char *frame;
testStart("Checking QRspec_newFrame with invalid version.");
frame = QRspec_newFrame(0);
assert_null(frame, "QRspec_newFrame(0) returns non-NULL.");
frame = QRspec_newFrame(QRSPEC_VERSION_MAX+1);
assert_null(frame, "QRspec_newFrame(0) returns non-NULL.");
testFinish();
}
#if 0
/* This test is used to check positions of alignment pattern. See Appendix E
* (p.71) of JIS X0510:2004 and compare to the output. Before comment out
* this test, change the value of the pattern marker's center dot from 0xa1
* to 0xb1 (QRspec_putAlignmentMarker() : finder).
*/
static void test_alignment(void)
{
unsigned char *frame;
int i, x, y, width, c;
testStart("Checking alignment pattern.");
for(i=2; i<=QRSPEC_VERSION_MAX; i++) {
printf("%2d", i);
frame = QRspec_newFrame(i);
width = QRspec_getWidth(i);
c = 0;
for(x=0; x<width * width; x++) {
if(frame[x] == 0xb1) {
c++;
}
}
printf("|%2d| 6", c);
y = width - 7;
for(x=0; x < width; x++) {
if(frame[y * width + x] == 0xb1) {
printf(", %3d", x);
}
}
printf("\n");
free(frame);
}
testFinish();
}
#endif
static void test_verpat(void)
{
int version;
unsigned int pattern;
int err = 0;
unsigned int data;
unsigned int code;
int i, c;
unsigned int mask;
testStart("Checking version pattern.");
for(version=7; version <= QRSPEC_VERSION_MAX; version++) {
pattern = QRspec_getVersionPattern(version);
if((pattern >> 12) != (unsigned int)version) {
printf("Error in version %d.\n", version);
err++;
continue;
}
mask = 0x40;
for(i=0; mask != 0; i++) {
if(version & mask) break;
mask = mask >> 1;
}
c = 6 - i;
data = version << 12;
code = 0x1f25 << c;
mask = 0x40000 >> (6 - c);
for(i=0; i<=c; i++) {
if(mask & data) {
data ^= code;
}
code = code >> 1;
mask = mask >> 1;
}
data = (version << 12) | (data & 0xfff);
if(data != pattern) {
printf("Error in version %d\n", version);
err++;
}
}
testEnd(err);
}
/* See Table 22 (p.45) and Appendix C (p. 65) of JIS X0510:2004 */
static unsigned int levelIndicator[4] = {1, 0, 3, 2};
static unsigned int calcFormatInfo(int mask, QRecLevel level)
{
unsigned int data, ecc, b, code;
int i, c;
data = (levelIndicator[level] << 13) | (mask << 10);
ecc = data;
b = 1 << 14;
for(i=0; b != 0; i++) {
if(ecc & b) break;
b = b >> 1;
}
c = 4 - i;
code = 0x537 << c ; //10100110111
b = 1 << (10 + c);
for(i=0; i<=c; i++) {
if(b & ecc) {
ecc ^= code;
}
code = code >> 1;
b = b >> 1;
}
return (data | ecc) ^ 0x5412;
}
static void test_format(void)
{
unsigned int format;
int i, j;
int err = 0;
testStart("Format info test");
for(i=0; i<4; i++) {
for(j=0; j<8; j++) {
format = calcFormatInfo(j, (QRecLevel)i);
// printf("0x%04x, ", format);
if(format != QRspec_getFormatInfo(j, (QRecLevel)i)) {
printf("Level %d, mask %x\n", i, j);
err++;
}
}
// printf("\n");
}
testEnd(err);
}
int main(int argc, char **argv)
{
int tests = 6;
testInit(tests);
test_eccTable();
test_eccTable2();
test_newframe();
test_newframe_invalid();
//test_alignment();
test_verpat();
test_format();
testReport(tests);
if(argc > 1) {
print_eccTable();
}
return 0;
}
@@ -0,0 +1,126 @@
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "../qrencode_inner.h"
#include "../qrspec.h"
#include "../mqrspec.h"
#include "../qrinput.h"
#include "../rsecc.h"
#include "decoder.h"
#include "rsecc_decoder.h"
#include "rscode.h"
/* See pp. 73 of JIS X0510:2004 */
void test_rscodeexample(void)
{
QRinput *stream;
QRRawCode *code;
static const char str[9] = "01234567";
static unsigned char correct[26] = {
0x10, 0x20, 0x0c, 0x56, 0x61, 0x80, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11,
0xec, 0x11, 0xec, 0x11, 0xa5, 0x24, 0xd4, 0xc1, 0xed, 0x36, 0xc7, 0x87,
0x2c, 0x55};
testStart("RS ecc test");
stream = QRinput_new();
QRinput_append(stream, QR_MODE_NUM, 8, (unsigned char *)str);
QRinput_setErrorCorrectionLevel(stream, QR_ECLEVEL_M);
code = QRraw_new(stream);
testEnd(memcmp(correct + 16, code->rsblock[0].ecc, 10));
QRinput_free(stream);
QRraw_free(code);
}
static void compareRS(unsigned char data[])
{
int i, j;
RS *rs;
int spec[5];
int dl, el;
unsigned char ecc_expected[256], ecc_rscodec[256];
for(i = 1; i <= QRSPEC_VERSION_MAX; i++) {
for(j = QR_ECLEVEL_L; j <= QR_ECLEVEL_H; j++) {
QRspec_getEccSpec(i, (QRecLevel)j, spec);
dl = QRspec_rsDataCodes1(spec);
el = QRspec_rsEccCodes1(spec);
rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el);
RSECC_encode(dl, el, data, ecc_rscodec);
encode_rs_char(rs, data, ecc_expected);
assert_zero(memcmp(ecc_expected, ecc_rscodec, el), "Invalid ECC found: length %d.\n", el);
assert_zero(RSECC_decoder_checkSyndrome(dl, data, el, ecc_rscodec), "ECC error found.");
free_rs_char(rs);
dl = QRspec_rsDataCodes2(spec);
el = QRspec_rsEccCodes2(spec);
if(dl != 0) {
rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el);
RSECC_encode(dl, el, data, ecc_rscodec);
encode_rs_char(rs, data, ecc_expected);
assert_zero(memcmp(ecc_expected, ecc_rscodec, el), "Invalid ECC found: length %d.\n", el);
assert_zero(RSECC_decoder_checkSyndrome(dl, data, el, ecc_rscodec), "ECC error found.");
free_rs_char(rs);
}
}
}
}
static void compareRSMQR(unsigned char data[])
{
int i, j;
RS *rs;
int dl, el;
unsigned char ecc_expected[256], ecc_rscodec[256];
for(i = 1; i <= MQRSPEC_VERSION_MAX; i++) {
for(j = QR_ECLEVEL_L; j <= QR_ECLEVEL_Q; j++) {
dl = MQRspec_getDataLength(i, (QRecLevel)j);
el = MQRspec_getECCLength(i, (QRecLevel)j);
if(dl != 0) {
rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el);
RSECC_encode(dl, el, data, ecc_rscodec);
encode_rs_char(rs, data, ecc_expected);
assert_zero(memcmp(ecc_expected, ecc_rscodec, el), "Invalid ECC found: length %d.\n", el);
assert_zero(RSECC_decoder_checkSyndrome(dl, data, el, ecc_rscodec), "ECC error found.");
free_rs_char(rs);
}
}
}
}
void test_allQRSizeAndECCLevel(void)
{
int i;
unsigned char data[256];
testStart("Comparing with KA9Q's code: all QR Code sizes and ECC levels");
memset(data, 0, 256);
compareRS(data);
compareRSMQR(data);
memset(data, 0xaa, 256);
compareRS(data);
compareRSMQR(data);
memset(data, 0xff, 256);
compareRS(data);
compareRSMQR(data);
for(i=0; i<256; i++) {
data[i] = i;
}
compareRS(data);
compareRSMQR(data);
testFinish();
}
int main()
{
RSECC_decoder_init();
int tests = 2;
testInit(tests);
test_rscodeexample();
test_allQRSizeAndECCLevel();
testReport(tests);
return 0;
}
@@ -0,0 +1,553 @@
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "common.h"
#include "../qrspec.h"
#include "../qrinput.h"
#include "../mask.h"
#include "../split.h"
#include "../bitstream.h"
static int inputTest(QRinput_List *list, const char *fmt, ...)
{
va_list ap;
int size;
QRencodeMode mode;
int i, err = 0;
va_start(ap, fmt);
i = 1;
while(*fmt) {
if(list == NULL) {
err = 1;
break;
}
size = va_arg(ap, int);
if(list->size != size) {
err = 1;
break;
}
switch(*fmt++) {
case 'n':
mode = QR_MODE_NUM;
break;
case 'a':
mode = QR_MODE_AN;
break;
case 'k':
mode = QR_MODE_KANJI;
break;
case '8':
mode = QR_MODE_8;
break;
default:
return -1;
break;
}
if(list->mode != mode) {
err = 1;
break;
}
list = list->next;
i++;
}
va_end(ap);
if(list != NULL) {
err = 1;
}
if(err) {
return -i;
}
return 0;
}
static int inputSize(QRinput *input)
{
BitStream *bstream;
int size;
bstream = BitStream_new();
QRinput_mergeBitStream(input, bstream);
size = BitStream_size(bstream);
BitStream_free(bstream);
return size;
}
static void test_split1(void)
{
QRinput *input;
BitStream *bstream;
testStart("Split test: null string");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("", input, QR_MODE_8, 0);
bstream = BitStream_new();
QRinput_mergeBitStream(input, bstream);
testEndExp(BitStream_size(bstream) == 0);
QRinput_free(input);
BitStream_free(bstream);
}
static void test_split2(void)
{
QRinput *input;
QRinput_List *list;
int err = 0;
testStart("Split test: single typed strings (num)");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("0123", input, QR_MODE_8, 0);
list = input->head;
if(inputTest(list, "n", 4)) {
err++;
}
testEnd(err);
QRinput_free(input);
err = 0;
testStart("Split test: single typed strings (num2)");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("12345678901234567890", input, QR_MODE_KANJI, 0);
list = input->head;
if(inputTest(list, "n", 20)) {
err++;
}
testEnd(err);
QRinput_free(input);
}
static void test_split3(void)
{
QRinput *input;
QRinput_List *list;
int err = 0;
testStart("Split test: single typed strings (an)");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("ab:-E", input, QR_MODE_8, 0);
list = input->head;
if(inputTest(list, "a", 5)) {
printQRinputInfo(input);
err++;
}
testEnd(err);
QRinput_free(input);
err = 0;
testStart("Split test: num + an");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("0123abcde", input, QR_MODE_KANJI, 0);
list = input->head;
if(inputTest(list, "a", 9)) {
err++;
}
testEnd(err);
QRinput_free(input);
err = 0;
testStart("Split test: an + num + an");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("Ab345fg", input, QR_MODE_KANJI, 0);
list = input->head;
if(inputTest(list, "a", 7)) {
err++;
}
testEnd(err);
QRinput_free(input);
}
static void test_split4(void)
{
QRinput *input;
QRinput *i1, *i2;
int s1, s2, size;
#define CHUNKA "ABCDEFGHIJK"
#define CHUNKB "123456"
#define CHUNKC "1234567"
testStart("Split test: an and num entries");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput(CHUNKA/**/CHUNKB, input, QR_MODE_8, 0);
i1 = QRinput_new();
QRinput_append(i1, QR_MODE_AN, 17, (unsigned char *)CHUNKA/**/CHUNKB);
i2 = QRinput_new();
QRinput_append(i2, QR_MODE_AN, 11, (unsigned char *)CHUNKA);
QRinput_append(i2, QR_MODE_NUM, 6, (unsigned char *)CHUNKB);
size = inputSize(input);
s1 = inputSize(i1);
s2 = inputSize(i2);
testEndExp(size == ((s1 < s2)?s1:s2));
QRinput_free(input);
QRinput_free(i1);
QRinput_free(i2);
testStart("Split test: num and an entries");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput(CHUNKB/**/CHUNKA, input, QR_MODE_8, 0);
i1 = QRinput_new();
QRinput_append(i1, QR_MODE_AN, 17, (unsigned char *)CHUNKB/**/CHUNKA);
i2 = QRinput_new();
QRinput_append(i2, QR_MODE_NUM, 6, (unsigned char *)CHUNKB);
QRinput_append(i2, QR_MODE_AN, 11, (unsigned char *)CHUNKA);
size = inputSize(input);
s1 = inputSize(i1);
s2 = inputSize(i2);
testEndExp(size == ((s1 < s2)?s1:s2));
QRinput_free(input);
QRinput_free(i1);
QRinput_free(i2);
testStart("Split test: num and an entries (should be splitted)");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput(CHUNKC/**/CHUNKA, input, QR_MODE_8, 0);
i1 = QRinput_new();
QRinput_append(i1, QR_MODE_AN, 18, (unsigned char *)CHUNKC/**/CHUNKA);
i2 = QRinput_new();
QRinput_append(i2, QR_MODE_NUM, 7, (unsigned char *)CHUNKC);
QRinput_append(i2, QR_MODE_AN, 11, (unsigned char *)CHUNKA);
size = inputSize(input);
s1 = inputSize(i1);
s2 = inputSize(i2);
testEndExp(size == ((s1 < s2)?s1:s2));
QRinput_free(input);
QRinput_free(i1);
QRinput_free(i2);
}
static void test_split5(void)
{
QRinput *input;
QRinput_List *list;
int err = 0;
testStart("Split test: bit, an, bit, num");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("\x82\xd9""abcdeabcdea\x82\xb0""123456", input, QR_MODE_8, 0);
list = input->head;
if(inputTest(list, "8a8n", 2, 11, 2, 6)) {
err++;
}
testEnd(err);
QRinput_free(input);
}
static void test_split6(void)
{
QRinput *input;
QRinput_List *list;
int err = 0;
testStart("Split test: kanji, an, kanji, num");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("\x82\xd9""abcdeabcdea\x82\xb0""123456", input, QR_MODE_KANJI, 0);
list = input->head;
if(inputTest(list, "kakn", 2, 11, 2, 6)) {
printQRinputInfo(input);
err++;
}
testEnd(err);
QRinput_free(input);
}
static void test_split7(void)
{
QRinput *input;
QRinput_List *list;
int err = 0;
testStart("Split test: an and num as bits");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("\x82\xd9""abcde\x82\xb0""12345", input, QR_MODE_8, 0);
list = input->head;
if(inputTest(list, "8n", 9, 5)) {
err++;
}
testEnd(err);
QRinput_free(input);
}
static void test_split8(void)
{
QRinput *input;
QRinput_List *list;
int err = 0;
testStart("Split test: terminated with a half of kanji code");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("\x82\xd9""abcdefgh\x82", input, QR_MODE_KANJI, 0);
list = input->head;
if(inputTest(list, "ka8", 2, 8, 1)) {
err++;
}
testEnd(err);
QRinput_free(input);
}
static void test_split3c(void)
{
QRinput *input;
QRinput_List *list;
int err = 0;
testStart("Split test: single typed strings (an, case-sensitive)");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("ab:-E", input, QR_MODE_8, 1);
list = input->head;
if(inputTest(list, "8", 5)) {
err++;
}
testEnd(err);
QRinput_free(input);
err = 0;
testStart("Split test: num + an");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("0123abcde", input, QR_MODE_KANJI, 1);
list = input->head;
if(inputTest(list, "n8", 4, 5)) {
err++;
}
testEnd(err);
QRinput_free(input);
err = 0;
testStart("Split test: an + num + an");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("Ab345fg", input, QR_MODE_KANJI, 1);
list = input->head;
if(inputTest(list, "8", 7)) {
printQRinputInfo(input);
err++;
}
testEnd(err);
QRinput_free(input);
}
static void test_toupper(void)
{
QRinput *input;
QRinput_List *list;
int err = 0;
testStart("Split test: check dupAndToUpper (lower->upper)");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("abcde", input, QR_MODE_8, 0);
list = input->head;
if(inputTest(list, "a", 5)) {
err++;
}
if(strncmp((char *)list->data, "ABCDE", list->size)) {
err++;
}
testEnd(err);
QRinput_free(input);
err = 0;
testStart("Split test: check dupAndToUpper (kanji)");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("\x83n\x83q\x83t\x83w\x83z", input, QR_MODE_KANJI, 0);
list = input->head;
if(inputTest(list, "k", 10)) {
printQRinputInfo(input);
err++;
}
if(strncmp((char *)list->data, "\x83n\x83q\x83t\x83w\x83z", list->size)) {
err++;
}
testEnd(err);
QRinput_free(input);
err = 0;
testStart("Split test: check dupAndToUpper (8bit)");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("\x83n\x83q\x83t\x83w\x83z", input, QR_MODE_8, 0);
list = input->head;
if(inputTest(list, "8", 10)) {
printQRinputInfo(input);
err++;
}
if(strncmp((char *)list->data, "\x83N\x83Q\x83T\x83W\x83Z", list->size)) {
err++;
}
testEnd(err);
QRinput_free(input);
}
static void test_splitNum8(void)
{
QRinput *input;
QRinput_List *list;
int err = 0;
testStart("Split test: num and 8bit to 8bit");
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput("1abcdefg", input, QR_MODE_8, 1);
list = input->head;
if(inputTest(list, "8", 8)) {
err++;
printQRinputInfo(input);
}
testEnd(err);
QRinput_free(input);
}
static void test_splitAnNAn(void)
{
QRinput *input1, *input2, *input3;
int s1, s2, s3;
char *strall = "326A80A9C5004C0875571F8B71C311F2F86";
char *str1 = "326A80A9C5004C";
char *str2 = "0875571";
char *str3 = "F8B71C311F2F86";
testStart("Split test: An-N-An switching cost test");
input1 = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput(strall, input1, QR_MODE_8, 0);
input2 = QRinput_new();
QRinput_append(input2, QR_MODE_AN, 35, (unsigned char *)strall);
input3 = QRinput_new();
QRinput_append(input3, QR_MODE_AN, 14, (unsigned char *)str1);
QRinput_append(input3, QR_MODE_NUM, 7, (unsigned char *)str2);
QRinput_append(input3, QR_MODE_AN, 14, (unsigned char *)str3);
s1 = inputSize(input1);
s2 = inputSize(input2);
s3 = inputSize(input3);
assert_equal(s1, s2, "Incorrect split");
assert_exp(s2 < s3, "Incorrect estimation");
testFinish();
QRinput_free(input1);
QRinput_free(input2);
QRinput_free(input3);
}
static void test_splitAn8An(void)
{
QRinput *input1, *input2, *input3;
int s1, s2, s3;
char *strall = "ABCDabcdefABCD";
char *str1 = "ABCD";
char *str2 = "abcdef";
char *str3 = "ABCD";
testStart("Split test: An-8-An switching cost test");
input1 = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput(strall, input1, QR_MODE_8, 1);
input2 = QRinput_new();
QRinput_append(input2, QR_MODE_8, 14, (unsigned char *)strall);
input3 = QRinput_new();
QRinput_append(input3, QR_MODE_AN, 4, (unsigned char *)str1);
QRinput_append(input3, QR_MODE_8, 6, (unsigned char *)str2);
QRinput_append(input3, QR_MODE_AN, 4, (unsigned char *)str3);
s1 = inputSize(input1);
s2 = inputSize(input2);
s3 = inputSize(input3);
assert_equal(s1, s2, "Incorrect split");
assert_exp(s2 < s3, "Incorrect estimation");
testFinish();
QRinput_free(input1);
QRinput_free(input2);
QRinput_free(input3);
}
static void test_split8An8(void)
{
QRinput *input1, *input2, *input3;
int s1, s2, s3;
char *strall = "abcABCDEFGHabc";
char *str1 = "abc";
char *str2 = "ABCDEFGH";
char *str3 = "abc";
testStart("Split test: 8-An-8 switching cost test");
input1 = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput(strall, input1, QR_MODE_8, 1);
input2 = QRinput_new();
QRinput_append(input2, QR_MODE_8, 14, (unsigned char *)strall);
input3 = QRinput_new();
QRinput_append(input3, QR_MODE_8, 3, (unsigned char *)str1);
QRinput_append(input3, QR_MODE_AN, 8, (unsigned char *)str2);
QRinput_append(input3, QR_MODE_8, 3, (unsigned char *)str3);
s1 = inputSize(input1);
s2 = inputSize(input2);
s3 = inputSize(input3);
assert_equal(s1, s2, "Incorrect split");
assert_exp(s2 < s3, "Incorrect estimation");
testFinish();
QRinput_free(input1);
QRinput_free(input2);
QRinput_free(input3);
}
static void test_split8N8(void)
{
QRinput *input1, *input2, *input3;
int s1, s2, s3;
char *strall = "abc1234abc";
char *str1 = "abc";
char *str2 = "1234";
char *str3 = "abc";
testStart("Split test: 8-N-8 switching cost test");
input1 = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput(strall, input1, QR_MODE_8, 1);
input2 = QRinput_new();
QRinput_append(input2, QR_MODE_8, 10, (unsigned char *)strall);
input3 = QRinput_new();
QRinput_append(input3, QR_MODE_8, 3, (unsigned char *)str1);
QRinput_append(input3, QR_MODE_NUM, 4, (unsigned char *)str2);
QRinput_append(input3, QR_MODE_8, 3, (unsigned char *)str3);
s1 = inputSize(input1);
s2 = inputSize(input2);
s3 = inputSize(input3);
assert_equal(s1, s2, "Incorrect split");
assert_exp(s2 < s3, "Incorrect estimation");
testFinish();
QRinput_free(input1);
QRinput_free(input2);
QRinput_free(input3);
}
int main()
{
int tests = 24;
testInit(tests);
test_split1();
test_split2();
test_split3();
test_split4();
test_split5();
test_split6();
test_split7();
test_split8();
test_split3c();
test_toupper();
test_splitNum8();
test_splitAnNAn();
test_splitAn8An();
test_split8An8();
test_split8N8();
testReport(tests);
return 0;
}
@@ -0,0 +1,92 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "common.h"
#include "../qrinput.h"
#include "../qrencode_inner.h"
#include "../split.h"
#include "decoder.h"
#include "URI_testset.inc"
#if 0
static void encodeURLandPrint(char *url) {
QRinput *input;
BitStream *bstream;
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput(url, input, QR_MODE_8, 1);
bstream = BitStream_new();
QRinput_mergeBitStream(input, bstream);
printf("{%zu,\"%s\"},\n", BitStream_size(bstream), url);
QRinput_free(input);
BitStream_free(bstream);
}
static void print_currentBitLength() {
struct TestSet *ts = testset;
puts("struct TestSet {\n\tint expected_length;\n\tchar *url;\n};");
puts("\nstruct TestSet testset[] = {");
while(ts->url != NULL) {
encodeURLandPrint(ts->url);
ts++;
}
puts("{0,NULL}\n};");
}
#endif
static int encodeURLandCompare(char *url, size_t expected_length) {
QRinput *input;
BitStream *bstream;
int ret = 0;
input = QRinput_new2(0, QR_ECLEVEL_L);
Split_splitStringToQRinput(url, input, QR_MODE_8, 1);
bstream = BitStream_new();
QRinput_mergeBitStream(input, bstream);
size_t length = BitStream_size(bstream);
if(length > expected_length) {
printf("The length of the encode stream is longer than expected: %zu over %zu\n", length, expected_length);
printQRinput(input);
ret = 1;
} else if(length < expected_length) {
printf("The length of the encode stream is shorter than expected: %zu under %zu\n", length, expected_length);
printQRinput(input);
ret = 1;
}
QRinput_free(input);
BitStream_free(bstream);
return ret;
}
static void test_bitstream_length() {
struct TestSet *ts = testset;
int err = 0;
testStart("Split_URL test: compare bitstream length");
while(ts->url != NULL) {
err += encodeURLandCompare(ts->url, ts->expected_length);
ts++;
}
testEnd(err);
}
int main()
{
int tests = 1;
testInit(tests);
test_bitstream_length();
testReport(tests);
return 0;
}
@@ -0,0 +1,641 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <SDL.h>
#include <getopt.h>
#include <errno.h>
#include "../config.h"
#include "../qrspec.h"
#include "../qrinput.h"
#include "../split.h"
#include "../qrencode_inner.h"
static SDL_Window *window;
static SDL_Renderer *renderer;
static SDL_Texture *texture = NULL;
static SDL_Surface *surface = NULL;
static int casesensitive = 1;
static int eightbit = 0;
static int version = 0;
static int size = 4;
static int margin = -1;
static int structured = 0;
static int micro = 0;
static int colorize = 0;
static QRecLevel level = QR_ECLEVEL_L;
static QRencodeMode hint = QR_MODE_8;
static char **textv;
static int textc;
static const struct option options[] = {
{"help" , no_argument , NULL, 'h'},
{"level" , required_argument, NULL, 'l'},
{"size" , required_argument, NULL, 's'},
{"symversion" , required_argument, NULL, 'v'},
{"margin" , required_argument, NULL, 'm'},
{"structured" , no_argument , NULL, 'S'},
{"kanji" , no_argument , NULL, 'k'},
{"casesensitive", no_argument , NULL, 'c'},
{"ignorecase" , no_argument , NULL, 'i'},
{"8bit" , no_argument , NULL, '8'},
{"micro" , no_argument , NULL, 'M'},
{"version" , no_argument , NULL, 'V'},
{NULL, 0, NULL, 0}
};
static char *optstring = "hl:s:v:m:Skci8MV";
static char levelChar[4] = {'L', 'M', 'Q', 'H'};
static void usage(int help, int longopt)
{
fprintf(stderr,
"view_qrcode version %s\n"
"Copyright (C) 2008, 2009, 2010 Kentaro Fukuchi\n", VERSION);
if(help) {
if(longopt) {
fprintf(stderr,
"Usage: view_qrcode [OPTION]... [STRING]\n"
"Encode input data in a QR Code and display.\n\n"
" -h, --help display the help message. -h displays only the help of short\n"
" options.\n\n"
" -s NUMBER, --size=NUMBER\n"
" specify module size in dots (pixels). (default=3)\n\n"
" -l {LMQH}, --level={LMQH}\n"
" specify error correction level from L (lowest) to H (highest).\n"
" (default=L)\n\n"
" -v NUMBER, --symversion=NUMBER\n"
" specify the version of the symbol. See SYMBOL VERSIONS for more\n"
" information. (default=auto)\n\n"
" -m NUMBER, --margin=NUMBER\n"
" specify the width of the margins. (default=4 (2 for Micro QR)))\n\n"
" -S, --structured\n"
" make structured symbols. Version must be specified.\n\n"
" -k, --kanji assume that the input text contains kanji (shift-jis).\n\n"
" -c, --casesensitive\n"
" encode lower-case alphabet characters in 8-bit mode. (default)\n\n"
" -i, --ignorecase\n"
" ignore case distinctions and use only upper-case characters.\n\n"
" -8, --8bit encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n\n"
" -M, --micro encode in a Micro QR Code. (experimental)\n\n"
" -V, --version\n"
" display the version number and copyrights of the qrencode.\n\n"
" [STRING] input data. If it is not specified, data will be taken from\n"
" standard input.\n\n"
"*SYMBOL VERSIONS\n"
" The symbol versions of QR Code range from Version 1 to Version\n"
" 40. Each version has a different module configuration or number\n"
" of modules, ranging from Version 1 (21 x 21 modules) up to\n"
" Version 40 (177 x 177 modules). Each higher version number\n"
" comprises 4 additional modules per side by default. See\n"
" http://www.qrcode.com/en/about/version.html for a detailed\n"
" version list.\n"
);
} else {
fprintf(stderr,
"Usage: view_qrcode [OPTION]... [STRING]\n"
"Encode input data in a QR Code and display.\n\n"
" -h display this message.\n"
" --help display the usage of long options.\n"
" -s NUMBER specify module size in dots (pixels). (default=3)\n"
" -l {LMQH} specify error correction level from L (lowest) to H (highest).\n"
" (default=L)\n"
" -v NUMBER specify the version of the symbol. (default=auto)\n"
" -m NUMBER specify the width of the margins. (default=4 (2 for Micro))\n"
" -S make structured symbols. Version must be specified.\n"
" -k assume that the input text contains kanji (shift-jis).\n"
" -c encode lower-case alphabet characters in 8-bit mode. (default)\n"
" -i ignore case distinctions and use only upper-case characters.\n"
" -8 encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n"
" -M encode in a Micro QR Code.\n"
" -V display the version number and copyrights of the qrencode.\n"
" [STRING] input data. If it is not specified, data will be taken from\n"
" standard input.\n"
);
}
}
}
#define MAX_DATA_SIZE (7090 * 16) /* from the specification */
static unsigned char *readStdin(int *length)
{
unsigned char *buffer;
int ret;
buffer = (unsigned char *)malloc(MAX_DATA_SIZE + 1);
if(buffer == NULL) {
fprintf(stderr, "Memory allocation failed.\n");
exit(EXIT_FAILURE);
}
ret = fread(buffer, 1, MAX_DATA_SIZE, stdin);
if(ret == 0) {
fprintf(stderr, "No input data.\n");
exit(EXIT_FAILURE);
}
if(feof(stdin) == 0) {
fprintf(stderr, "Input data is too large.\n");
exit(EXIT_FAILURE);
}
buffer[ret] = '\0';
*length = ret;
return buffer;
}
static void draw_QRcode(QRcode *qrcode, int ox, int oy)
{
int x, y, width;
unsigned char *p;
SDL_Rect rect;
Uint32 color[8];
int col;
color[0] = SDL_MapRGBA(surface->format, 255, 255, 255, 255);
color[1] = SDL_MapRGBA(surface->format, 0, 0, 0, 255);
color[2] = SDL_MapRGBA(surface->format, 192, 192, 255, 255);
color[3] = SDL_MapRGBA(surface->format, 0, 0, 64, 255);
color[4] = SDL_MapRGBA(surface->format, 255, 255, 192, 255);
color[5] = SDL_MapRGBA(surface->format, 64, 64, 0, 255);
color[6] = SDL_MapRGBA(surface->format, 255, 192, 192, 255);
color[7] = SDL_MapRGBA(surface->format, 64, 0, 0, 255);
ox += margin * size;
oy += margin * size;
width = qrcode->width;
p = qrcode->data;
for(y=0; y<width; y++) {
for(x=0; x<width; x++) {
rect.x = ox + x * size;
rect.y = oy + y * size;
rect.w = size;
rect.h = size;
if(!colorize) {
col = 0;
} else {
if(*p & 0x80) {
col = 6;
} else if(*p & 0x02) {
col = 4;
} else {
col = 2;
}
}
col += (*p & 1);
SDL_FillRect(surface, &rect, color[col]);
p++;
}
}
}
static void draw_singleQRcode(QRinput *stream, int mask)
{
QRcode *qrcode;
int width;
QRinput_setVersionAndErrorCorrectionLevel(stream, version, level);
if(micro) {
qrcode = QRcode_encodeMaskMQR(stream, mask);
} else {
qrcode = QRcode_encodeMask(stream, mask);
}
if(qrcode == NULL) {
width = (11 + margin * 2) * size;
fprintf(stderr, "Input data does not fit to this setting.\n");
} else {
version = qrcode->version;
width = (qrcode->width + margin * 2) * size;
}
SDL_SetWindowSize(window, width, width);
if(surface != NULL) {
SDL_FreeSurface(surface);
}
surface = SDL_CreateRGBSurface(0, width, width, 32, 0, 0, 0, 0);
SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, 255, 255, 255, 255));
if(qrcode) {
draw_QRcode(qrcode, 0, 0);
}
if(texture != NULL) {
SDL_DestroyTexture(texture);
}
texture = SDL_CreateTextureFromSurface(renderer, surface);
QRcode_free(qrcode);
}
static void draw_structuredQRcode(QRinput_Struct *s)
{
int i, w, h, n, x, y;
int swidth;
QRcode_List *qrcodes, *p;
qrcodes = QRcode_encodeInputStructured(s);
if(qrcodes == NULL) return;
swidth = (qrcodes->code->width + margin * 2) * size;
n = QRcode_List_size(qrcodes);
w = (n < 4)?n:4;
h = (n - 1) / 4 + 1;
SDL_SetWindowSize(window, swidth * w, swidth * h);
if(surface != NULL) {
SDL_FreeSurface(surface);
}
surface = SDL_CreateRGBSurface(0, swidth * w, swidth * h, 32, 0, 0, 0, 0);
SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, 255, 255, 255, 255));
p = qrcodes;
for(i=0; i<n; i++) {
x = (i % 4) * swidth;
y = (i / 4) * swidth;
draw_QRcode(p->code, x, y);
p = p->next;
}
if(texture != NULL) {
SDL_DestroyTexture(texture);
}
texture = SDL_CreateTextureFromSurface(renderer, surface);
QRcode_List_free(qrcodes);
}
static void draw_structuredQRcodeFromText(int argc, char **argv)
{
QRinput_Struct *s;
QRinput *input;
int i, ret;
s = QRinput_Struct_new();
if(s == NULL) {
fprintf(stderr, "Failed to allocate memory.\n");
exit(EXIT_FAILURE);
}
for(i=0; i<argc; i++) {
input = QRinput_new2(version, level);
if(input == NULL) {
fprintf(stderr, "Failed to allocate memory.\n");
exit(EXIT_FAILURE);
}
if(eightbit) {
ret = QRinput_append(input, QR_MODE_8, strlen(argv[i]), (unsigned char *)argv[i]);
} else {
ret = Split_splitStringToQRinput(argv[i], input, hint, casesensitive);
}
if(ret < 0) {
perror("Encoding the input string");
exit(EXIT_FAILURE);
}
ret = QRinput_Struct_appendInput(s, input);
if(ret < 0) {
perror("Encoding the input string");
exit(EXIT_FAILURE);
}
}
ret = QRinput_Struct_insertStructuredAppendHeaders(s);
if(ret < 0) {
fprintf(stderr, "Too many inputs.\n");
}
draw_structuredQRcode(s);
QRinput_Struct_free(s);
}
static void draw_structuredQRcodeFromQRinput(QRinput *stream)
{
QRinput_Struct *s;
QRinput_setVersion(stream, version);
QRinput_setErrorCorrectionLevel(stream, level);
s = QRinput_splitQRinputToStruct(stream);
if(s != NULL) {
draw_structuredQRcode(s);
QRinput_Struct_free(s);
} else {
fprintf(stderr, "Input data is too large for this setting.\n");
}
}
static void view(int mode, QRinput *input)
{
int flag = 1;
int mask = -1;
SDL_Event event;
int loop;
int codeChanged = 1;
while(flag) {
if(codeChanged) {
if(mode) {
draw_structuredQRcodeFromText(textc, textv);
} else {
if(structured) {
draw_structuredQRcodeFromQRinput(input);
} else {
draw_singleQRcode(input, mask);
}
}
if(mode || structured) {
printf("Version %d, Level %c.\n", version, levelChar[level]);
} else {
printf("Version %d, Level %c, Mask %d.\n", version, levelChar[level], mask);
}
}
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
loop = 1;
codeChanged = 0;
while(loop) {
SDL_WaitEvent(&event);
if(event.type == SDL_KEYDOWN) {
codeChanged = 1;
switch(event.key.keysym.sym) {
case SDLK_RIGHT:
version++;
if(version > QRSPEC_VERSION_MAX)
version = QRSPEC_VERSION_MAX;
loop = 0;
break;
case SDLK_LEFT:
version--;
if(version < 1)
version = 1;
loop = 0;
break;
case SDLK_UP:
size++;
loop = 0;
break;
case SDLK_DOWN:
size--;
if(size < 1) size = 1;
loop = 0;
break;
case SDLK_0:
case SDLK_1:
case SDLK_2:
case SDLK_3:
case SDLK_4:
case SDLK_5:
case SDLK_6:
case SDLK_7:
if(!mode && !structured) {
mask = (event.key.keysym.sym - SDLK_0);
loop = 0;
}
break;
case SDLK_8:
if(!mode && !structured) {
mask = -1;
loop = 0;
}
break;
case SDLK_9:
if(!mode && !structured) {
mask = -2;
loop = 0;
}
break;
case SDLK_l:
level = QR_ECLEVEL_L;
loop = 0;
break;
case SDLK_m:
level = QR_ECLEVEL_M;
loop = 0;
break;
case SDLK_h:
level = QR_ECLEVEL_H;
loop = 0;
break;
case SDLK_q:
level = QR_ECLEVEL_Q;
loop = 0;
break;
case SDLK_c:
colorize ^= 1;
loop = 0;
break;
case SDLK_ESCAPE:
loop = 0;
flag = 0;
break;
default:
break;
}
if(event.type == SDL_QUIT) {
loop = 0;
flag = 0;
}
}
if (event.type == SDL_WINDOWEVENT) {
switch (event.window.event) {
case SDL_WINDOWEVENT_SHOWN:
case SDL_WINDOWEVENT_EXPOSED:
case SDL_WINDOWEVENT_SIZE_CHANGED:
case SDL_WINDOWEVENT_RESIZED:
loop = 0;
break;
default:
break;
}
}
}
}
}
static void view_simple(const unsigned char *str, int length)
{
QRinput *input;
int ret;
if(micro) {
input = QRinput_newMQR(version, level);
} else {
input = QRinput_new2(version, level);
}
if(input == NULL) {
fprintf(stderr, "Memory allocation error.\n");
exit(EXIT_FAILURE);
}
if(eightbit) {
ret = QRinput_append(input, QR_MODE_8, length, str);
} else {
ret = Split_splitStringToQRinput((char *)str, input, hint, casesensitive);
}
if(ret < 0) {
perror("Encoding the input string");
exit(EXIT_FAILURE);
}
view(0, input);
QRinput_free(input);
}
static void view_multiText(char **argv, int argc)
{
textc = argc;
textv = argv;
view(1, NULL);
}
int main(int argc, char **argv)
{
int opt, lindex = -1;
unsigned char *intext = NULL;
int length = 0;
int ret;
while((opt = getopt_long(argc, argv, optstring, options, &lindex)) != -1) {
switch(opt) {
case 'h':
if(lindex == 0) {
usage(1, 1);
} else {
usage(1, 0);
}
exit(EXIT_SUCCESS);
break;
case 's':
size = atoi(optarg);
if(size <= 0) {
fprintf(stderr, "Invalid size: %d\n", size);
exit(EXIT_FAILURE);
}
break;
case 'v':
version = atoi(optarg);
if(version < 0) {
fprintf(stderr, "Invalid version: %d\n", version);
exit(EXIT_FAILURE);
}
break;
case 'l':
switch(*optarg) {
case 'l':
case 'L':
level = QR_ECLEVEL_L;
break;
case 'm':
case 'M':
level = QR_ECLEVEL_M;
break;
case 'q':
case 'Q':
level = QR_ECLEVEL_Q;
break;
case 'h':
case 'H':
level = QR_ECLEVEL_H;
break;
default:
fprintf(stderr, "Invalid level: %s\n", optarg);
exit(EXIT_FAILURE);
break;
}
break;
case 'm':
margin = atoi(optarg);
if(margin < 0) {
fprintf(stderr, "Invalid margin: %d\n", margin);
exit(EXIT_FAILURE);
}
break;
case 'S':
structured = 1;
case 'k':
hint = QR_MODE_KANJI;
break;
case 'c':
casesensitive = 1;
break;
case 'i':
casesensitive = 0;
break;
case '8':
eightbit = 1;
break;
case 'M':
micro = 1;
break;
case 'V':
usage(0, 0);
exit(EXIT_SUCCESS);
break;
default:
fprintf(stderr, "Try `view_qrcode --help' for more information.\n");
exit(EXIT_FAILURE);
break;
}
}
if(argc == 1) {
usage(1, 0);
exit(EXIT_SUCCESS);
}
if(optind < argc) {
intext = (unsigned char *)argv[optind];
length = strlen((char *)intext);
}
if(intext == NULL) {
intext = readStdin(&length);
}
if(micro && version > MQRSPEC_VERSION_MAX) {
fprintf(stderr, "Version should be less or equal to %d.\n", MQRSPEC_VERSION_MAX);
exit(EXIT_FAILURE);
} else if(!micro && version > QRSPEC_VERSION_MAX) {
fprintf(stderr, "Version should be less or equal to %d.\n", QRSPEC_VERSION_MAX);
exit(EXIT_FAILURE);
}
if(margin < 0) {
if(micro) {
margin = 2;
} else {
margin = 4;
}
}
if(micro) {
if(version == 0) {
fprintf(stderr, "Version must be specified to encode a Micro QR Code symbol.\n");
exit(EXIT_FAILURE);
}
if(structured) {
fprintf(stderr, "Micro QR Code does not support structured symbols.\n");
exit(EXIT_FAILURE);
}
}
if(structured && version == 0) {
fprintf(stderr, "Version must be specified to encode structured symbols.\n");
exit(EXIT_FAILURE);
}
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
fprintf(stderr, "Failed initializing SDL: %s\n", SDL_GetError());
return -1;
}
ret = SDL_CreateWindowAndRenderer(100, 100, SDL_WINDOW_SHOWN, &window, &renderer);
if(ret < 0) {
fprintf(stderr, "Failed to create a window: %s\n", SDL_GetError());
return -1;
}
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
if(structured && (argc - optind > 1)) {
view_multiText(argv + optind, argc - optind);
} else {
view_simple(intext, length);
}
SDL_Quit();
return 0;
}