|  | /* | 
|  | * 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 | 
|  | } |