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