Advance KDE Plasma and Qt integration
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,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 */
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh -e
|
||||
. ./test_basic.sh
|
||||
./test_configure.sh
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user