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