blob: 76d2d261a64c236a9a11ed8d8b4e4b8362e1608c [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/*
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}