1/*
2 * qrencode - QR Code encoder
3 *
4 * Micor QR Code specification in convenient format.
5 * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
6 *
7 * The following data / specifications are taken from
8 * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
9 *  or
10 * "Automatic identification and data capture techniques --
11 *  QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 */
27
28#if HAVE_CONFIG_H
29# include "config.h"
30#endif
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <errno.h>
35#ifdef HAVE_LIBPTHREAD
36#include <pthread.h>
37#endif
38
39#include "mqrspec.h"
40
41/******************************************************************************
42 * Version and capacity
43 *****************************************************************************/
44
45typedef struct {
46	int width; //< Edge length of the symbol
47	int ec[4];  //< Number of ECC code (bytes)
48} MQRspec_Capacity;
49
50/**
51 * Table of the capacity of symbols
52 * See Table 1 (pp.106) and Table 8 (pp.113) of Appendix 1, JIS X0510:2004.
53 */
54static const MQRspec_Capacity mqrspecCapacity[MQRSPEC_VERSION_MAX + 1] = {
55	{  0, {0,  0,  0, 0}},
56	{ 11, {2,  0,  0, 0}},
57	{ 13, {5,  6,  0, 0}},
58	{ 15, {6,  8,  0, 0}},
59	{ 17, {8, 10, 14, 0}}
60};
61
62int MQRspec_getDataLengthBit(int version, QRecLevel level)
63{
64	int w;
65	int ecc;
66
67	w = mqrspecCapacity[version].width - 1;
68	ecc = mqrspecCapacity[version].ec[level];
69	if(ecc == 0) return 0;
70	return w * w - 64 - ecc * 8;
71}
72
73int MQRspec_getDataLength(int version, QRecLevel level)
74{
75	return (MQRspec_getDataLengthBit(version, level) + 4) / 8;
76}
77
78int MQRspec_getECCLength(int version, QRecLevel level)
79{
80	return mqrspecCapacity[version].ec[level];
81}
82
83int MQRspec_getWidth(int version)
84{
85	return mqrspecCapacity[version].width;
86}
87
88/******************************************************************************
89 * Length indicator
90 *****************************************************************************/
91
92/**
93 * See Table 3 (pp.107) of Appendix 1, JIS X0510:2004.
94 */
95static const int lengthTableBits[4][4] = {
96	{ 3, 4, 5, 6},
97	{ 0, 3, 4, 5},
98	{ 0, 0, 4, 5},
99	{ 0, 0, 3, 4}
100};
101
102int MQRspec_lengthIndicator(QRencodeMode mode, int version)
103{
104	return lengthTableBits[mode][version - 1];
105}
106
107int MQRspec_maximumWords(QRencodeMode mode, int version)
108{
109	int bits;
110	int words;
111
112	bits = lengthTableBits[mode][version - 1];
113	words = (1 << bits) - 1;
114	if(mode == QR_MODE_KANJI) {
115		words *= 2; // the number of bytes is required
116	}
117
118	return words;
119}
120
121/******************************************************************************
122 * Format information
123 *****************************************************************************/
124
125/* See calcFormatInfo in tests/test_mqrspec.c */
126static const unsigned int formatInfo[4][8] = {
127	{0x4445, 0x55ae, 0x6793, 0x7678, 0x06de, 0x1735, 0x2508, 0x34e3},
128	{0x4172, 0x5099, 0x62a4, 0x734f, 0x03e9, 0x1202, 0x203f, 0x31d4},
129	{0x4e2b, 0x5fc0, 0x6dfd, 0x7c16, 0x0cb0, 0x1d5b, 0x2f66, 0x3e8d},
130	{0x4b1c, 0x5af7, 0x68ca, 0x7921, 0x0987, 0x186c, 0x2a51, 0x3bba}
131};
132
133/* See Table 10 of Appendix 1. (pp.115) */
134static const int typeTable[MQRSPEC_VERSION_MAX + 1][3] = {
135	{-1, -1, -1},
136	{ 0, -1, -1},
137	{ 1,  2, -1},
138	{ 3,  4, -1},
139	{ 5,  6,  7}
140};
141
142unsigned int MQRspec_getFormatInfo(int mask, int version, QRecLevel level)
143{
144	int type;
145
146	if(mask < 0 || mask > 3) return 0;
147	if(version <= 0 || version > MQRSPEC_VERSION_MAX) return 0;
148	if(level == QR_ECLEVEL_H) return 0;
149	type = typeTable[version][level];
150	if(type < 0) return 0;
151
152	return formatInfo[mask][type];
153}
154
155/******************************************************************************
156 * Frame
157 *****************************************************************************/
158
159/**
160 * Cache of initial frames.
161 */
162/* C99 says that static storage shall be initialized to a null pointer
163 * by compiler. */
164static unsigned char *frames[MQRSPEC_VERSION_MAX + 1];
165#ifdef HAVE_LIBPTHREAD
166static pthread_mutex_t frames_mutex = PTHREAD_MUTEX_INITIALIZER;
167#endif
168
169/**
170 * Put a finder pattern.
171 * @param frame
172 * @param width
173 * @param ox,oy upper-left coordinate of the pattern
174 */
175static void putFinderPattern(unsigned char *frame, int width, int ox, int oy)
176{
177	static const unsigned char finder[] = {
178		0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
179		0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
180		0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
181		0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
182		0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
183		0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
184		0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
185	};
186	int x, y;
187	const unsigned char *s;
188
189	frame += oy * width + ox;
190	s = finder;
191	for(y=0; y<7; y++) {
192		for(x=0; x<7; x++) {
193			frame[x] = s[x];
194		}
195		frame += width;
196		s += 7;
197	}
198}
199
200static unsigned char *MQRspec_createFrame(int version)
201{
202	unsigned char *frame, *p, *q;
203	int width;
204	int x, y;
205
206	width = mqrspecCapacity[version].width;
207	frame = (unsigned char *)malloc(width * width);
208	if(frame == NULL) return NULL;
209
210	memset(frame, 0, width * width);
211	/* Finder pattern */
212	putFinderPattern(frame, width, 0, 0);
213	/* Separator */
214	p = frame;
215	for(y=0; y<7; y++) {
216		p[7] = 0xc0;
217		p += width;
218	}
219	memset(frame + width * 7, 0xc0, 8);
220	/* Mask format information area */
221	memset(frame + width * 8 + 1, 0x84, 8);
222	p = frame + width + 8;
223	for(y=0; y<7; y++) {
224		*p = 0x84;
225		p += width;
226	}
227	/* Timing pattern */
228	p = frame + 8;
229	q = frame + width * 8;
230	for(x=1; x<width-7; x++) {
231		*p =  0x90 | (x & 1);
232		*q =  0x90 | (x & 1);
233		p++;
234		q += width;
235	}
236
237	return frame;
238}
239
240unsigned char *MQRspec_newFrame(int version)
241{
242	unsigned char *frame;
243	int width;
244
245	if(version < 1 || version > MQRSPEC_VERSION_MAX) return NULL;
246
247#ifdef HAVE_LIBPTHREAD
248	pthread_mutex_lock(&frames_mutex);
249#endif
250	if(frames[version] == NULL) {
251		frames[version] = MQRspec_createFrame(version);
252	}
253#ifdef HAVE_LIBPTHREAD
254	pthread_mutex_unlock(&frames_mutex);
255#endif
256	if(frames[version] == NULL) return NULL;
257
258	width = mqrspecCapacity[version].width;
259	frame = (unsigned char *)malloc(width * width);
260	if(frame == NULL) return NULL;
261	memcpy(frame, frames[version], width * width);
262
263	return frame;
264}
265
266void MQRspec_clearCache(void)
267{
268	int i;
269
270#ifdef HAVE_LIBPTHREAD
271	pthread_mutex_lock(&frames_mutex);
272#endif
273	for(i=1; i<=MQRSPEC_VERSION_MAX; i++) {
274		free(frames[i]);
275		frames[i] = NULL;
276	}
277#ifdef HAVE_LIBPTHREAD
278	pthread_mutex_unlock(&frames_mutex);
279#endif
280}
281