| /* | 
 |  * qrencode - QR Code encoder | 
 |  * | 
 |  * Micor QR Code specification in convenient format.  | 
 |  * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org> | 
 |  * | 
 |  * The following data / specifications are taken from | 
 |  * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) | 
 |  *  or | 
 |  * "Automatic identification and data capture techniques --  | 
 |  *  QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) | 
 |  * | 
 |  * 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 <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <errno.h> | 
 | #ifdef HAVE_LIBPTHREAD | 
 | #include <pthread.h> | 
 | #endif | 
 |  | 
 | #include "mqrspec.h" | 
 |  | 
 | /****************************************************************************** | 
 |  * Version and capacity | 
 |  *****************************************************************************/ | 
 |  | 
 | typedef struct { | 
 | 	int width; //< Edge length of the symbol | 
 | 	int ec[4];  //< Number of ECC code (bytes) | 
 | } MQRspec_Capacity; | 
 |  | 
 | /** | 
 |  * Table of the capacity of symbols | 
 |  * See Table 1 (pp.106) and Table 8 (pp.113) of Appendix 1, JIS X0510:2004. | 
 |  */ | 
 | static const MQRspec_Capacity mqrspecCapacity[MQRSPEC_VERSION_MAX + 1] = { | 
 | 	{  0, {0,  0,  0, 0}}, | 
 | 	{ 11, {2,  0,  0, 0}}, | 
 | 	{ 13, {5,  6,  0, 0}}, | 
 | 	{ 15, {6,  8,  0, 0}}, | 
 | 	{ 17, {8, 10, 14, 0}} | 
 | }; | 
 |  | 
 | int MQRspec_getDataLengthBit(int version, QRecLevel level) | 
 | { | 
 | 	int w; | 
 | 	int ecc; | 
 |  | 
 | 	w = mqrspecCapacity[version].width - 1; | 
 | 	ecc = mqrspecCapacity[version].ec[level]; | 
 | 	if(ecc == 0) return 0; | 
 | 	return w * w - 64 - ecc * 8; | 
 | } | 
 |  | 
 | int MQRspec_getDataLength(int version, QRecLevel level) | 
 | { | 
 | 	return (MQRspec_getDataLengthBit(version, level) + 4) / 8; | 
 | } | 
 |  | 
 | int MQRspec_getECCLength(int version, QRecLevel level) | 
 | { | 
 | 	return mqrspecCapacity[version].ec[level]; | 
 | } | 
 |  | 
 | int MQRspec_getWidth(int version) | 
 | { | 
 | 	return mqrspecCapacity[version].width; | 
 | } | 
 |  | 
 | /****************************************************************************** | 
 |  * Length indicator | 
 |  *****************************************************************************/ | 
 |  | 
 | /** | 
 |  * See Table 3 (pp.107) of Appendix 1, JIS X0510:2004. | 
 |  */ | 
 | static const int lengthTableBits[4][4] = { | 
 | 	{ 3, 4, 5, 6}, | 
 | 	{ 0, 3, 4, 5}, | 
 | 	{ 0, 0, 4, 5}, | 
 | 	{ 0, 0, 3, 4} | 
 | }; | 
 |  | 
 | int MQRspec_lengthIndicator(QRencodeMode mode, int version) | 
 | { | 
 | 	return lengthTableBits[mode][version - 1]; | 
 | } | 
 |  | 
 | int MQRspec_maximumWords(QRencodeMode mode, int version) | 
 | { | 
 | 	int bits; | 
 | 	int words; | 
 |  | 
 | 	bits = lengthTableBits[mode][version - 1]; | 
 | 	words = (1 << bits) - 1; | 
 | 	if(mode == QR_MODE_KANJI) { | 
 | 		words *= 2; // the number of bytes is required | 
 | 	} | 
 |  | 
 | 	return words; | 
 | } | 
 |  | 
 | /****************************************************************************** | 
 |  * Format information | 
 |  *****************************************************************************/ | 
 |  | 
 | /* See calcFormatInfo in tests/test_mqrspec.c */ | 
 | static const unsigned int formatInfo[4][8] = { | 
 | 	{0x4445, 0x55ae, 0x6793, 0x7678, 0x06de, 0x1735, 0x2508, 0x34e3}, | 
 | 	{0x4172, 0x5099, 0x62a4, 0x734f, 0x03e9, 0x1202, 0x203f, 0x31d4}, | 
 | 	{0x4e2b, 0x5fc0, 0x6dfd, 0x7c16, 0x0cb0, 0x1d5b, 0x2f66, 0x3e8d}, | 
 | 	{0x4b1c, 0x5af7, 0x68ca, 0x7921, 0x0987, 0x186c, 0x2a51, 0x3bba} | 
 | }; | 
 |  | 
 | /* See Table 10 of Appendix 1. (pp.115) */ | 
 | static const int typeTable[MQRSPEC_VERSION_MAX + 1][3] = { | 
 | 	{-1, -1, -1}, | 
 | 	{ 0, -1, -1}, | 
 | 	{ 1,  2, -1}, | 
 | 	{ 3,  4, -1}, | 
 | 	{ 5,  6,  7} | 
 | }; | 
 |  | 
 | unsigned int MQRspec_getFormatInfo(int mask, int version, QRecLevel level) | 
 | { | 
 | 	int type; | 
 |  | 
 | 	if(mask < 0 || mask > 3) return 0; | 
 | 	if(version <= 0 || version > MQRSPEC_VERSION_MAX) return 0; | 
 | 	if(level == QR_ECLEVEL_H) return 0; | 
 | 	type = typeTable[version][level]; | 
 | 	if(type < 0) return 0; | 
 |  | 
 | 	return formatInfo[mask][type]; | 
 | } | 
 |  | 
 | /****************************************************************************** | 
 |  * Frame | 
 |  *****************************************************************************/ | 
 |  | 
 | /** | 
 |  * Cache of initial frames. | 
 |  */ | 
 | /* C99 says that static storage shall be initialized to a null pointer | 
 |  * by compiler. */ | 
 | static unsigned char *frames[MQRSPEC_VERSION_MAX + 1]; | 
 | #ifdef HAVE_LIBPTHREAD | 
 | static pthread_mutex_t frames_mutex = PTHREAD_MUTEX_INITIALIZER; | 
 | #endif | 
 |  | 
 | /** | 
 |  * Put a finder pattern. | 
 |  * @param frame | 
 |  * @param width | 
 |  * @param ox,oy upper-left coordinate of the pattern | 
 |  */ | 
 | static void putFinderPattern(unsigned char *frame, int width, int ox, int oy) | 
 | { | 
 | 	static const unsigned char finder[] = { | 
 | 		0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, | 
 | 		0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, | 
 | 		0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, | 
 | 		0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, | 
 | 		0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, | 
 | 		0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, | 
 | 		0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, | 
 | 	}; | 
 | 	int x, y; | 
 | 	const unsigned char *s; | 
 |  | 
 | 	frame += oy * width + ox; | 
 | 	s = finder; | 
 | 	for(y=0; y<7; y++) { | 
 | 		for(x=0; x<7; x++) { | 
 | 			frame[x] = s[x]; | 
 | 		} | 
 | 		frame += width; | 
 | 		s += 7; | 
 | 	} | 
 | } | 
 |  | 
 | static unsigned char *MQRspec_createFrame(int version) | 
 | { | 
 | 	unsigned char *frame, *p, *q; | 
 | 	int width; | 
 | 	int x, y; | 
 |  | 
 | 	width = mqrspecCapacity[version].width; | 
 | 	frame = (unsigned char *)malloc(width * width); | 
 | 	if(frame == NULL) return NULL; | 
 |  | 
 | 	memset(frame, 0, width * width); | 
 | 	/* Finder pattern */ | 
 | 	putFinderPattern(frame, width, 0, 0); | 
 | 	/* Separator */ | 
 | 	p = frame; | 
 | 	for(y=0; y<7; y++) { | 
 | 		p[7] = 0xc0; | 
 | 		p += width; | 
 | 	} | 
 | 	memset(frame + width * 7, 0xc0, 8); | 
 | 	/* Mask format information area */ | 
 | 	memset(frame + width * 8 + 1, 0x84, 8); | 
 | 	p = frame + width + 8; | 
 | 	for(y=0; y<7; y++) { | 
 | 		*p = 0x84; | 
 | 		p += width; | 
 | 	} | 
 | 	/* Timing pattern */ | 
 | 	p = frame + 8; | 
 | 	q = frame + width * 8; | 
 | 	for(x=1; x<width-7; x++) { | 
 | 		*p =  0x90 | (x & 1); | 
 | 		*q =  0x90 | (x & 1); | 
 | 		p++; | 
 | 		q += width; | 
 | 	} | 
 |  | 
 | 	return frame; | 
 | } | 
 |  | 
 | unsigned char *MQRspec_newFrame(int version) | 
 | { | 
 | 	unsigned char *frame; | 
 | 	int width; | 
 |  | 
 | 	if(version < 1 || version > MQRSPEC_VERSION_MAX) return NULL; | 
 |  | 
 | #ifdef HAVE_LIBPTHREAD | 
 | 	pthread_mutex_lock(&frames_mutex); | 
 | #endif | 
 | 	if(frames[version] == NULL) { | 
 | 		frames[version] = MQRspec_createFrame(version); | 
 | 	} | 
 | #ifdef HAVE_LIBPTHREAD | 
 | 	pthread_mutex_unlock(&frames_mutex); | 
 | #endif | 
 | 	if(frames[version] == NULL) return NULL; | 
 |  | 
 | 	width = mqrspecCapacity[version].width; | 
 | 	frame = (unsigned char *)malloc(width * width); | 
 | 	if(frame == NULL) return NULL; | 
 | 	memcpy(frame, frames[version], width * width); | 
 |  | 
 | 	return frame; | 
 | } | 
 |  | 
 | void MQRspec_clearCache(void) | 
 | { | 
 | 	int i; | 
 |  | 
 | #ifdef HAVE_LIBPTHREAD | 
 | 	pthread_mutex_lock(&frames_mutex); | 
 | #endif | 
 | 	for(i=1; i<=MQRSPEC_VERSION_MAX; i++) { | 
 | 		free(frames[i]); | 
 | 		frames[i] = NULL; | 
 | 	} | 
 | #ifdef HAVE_LIBPTHREAD | 
 | 	pthread_mutex_unlock(&frames_mutex); | 
 | #endif | 
 | } |