]> git.sur5r.net Git - glabels/blob - qrencode-3.1.0/split.c
4bb8e55b1c13f406d702840c143b01761d5326a8
[glabels] / qrencode-3.1.0 / split.c
1 /*
2  * qrencode - QR Code encoder
3  *
4  * Input data splitter.
5  * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
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 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include "qrencode.h"
32 #include "qrinput.h"
33 #include "qrspec.h"
34 #include "split.h"
35
36 #define isdigit(__c__) ((unsigned char)((signed char)(__c__) - '0') < 10)
37 #define isalnum(__c__) (QRinput_lookAnTable(__c__) >= 0)
38
39 static QRencodeMode Split_identifyMode(const char *string, QRencodeMode hint)
40 {
41         unsigned char c, d;
42         unsigned int word;
43
44         c = string[0];
45
46         if(c == '\0') return QR_MODE_NUL;
47         if(isdigit(c)) {
48                 return QR_MODE_NUM;
49         } else if(isalnum(c)) {
50                 return QR_MODE_AN;
51         } else if(hint == QR_MODE_KANJI) {
52                 d = string[1];
53                 if(d != '\0') {
54                         word = ((unsigned int)c << 8) | d;
55                         if((word >= 0x8140 && word <= 0x9ffc) || (word >= 0xe040 && word <= 0xebbf)) {
56                                 return QR_MODE_KANJI;
57                         }
58                 }
59         }
60
61         return QR_MODE_8;
62 }
63
64 static int Split_eatNum(const char *string, QRinput *input, QRencodeMode hint);
65 static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint);
66 static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint);
67 static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint);
68
69 static int Split_eatNum(const char *string, QRinput *input,QRencodeMode hint)
70 {
71         const char *p;
72         int ret;
73         int run;
74         int dif;
75         int ln;
76         QRencodeMode mode;
77
78         ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
79
80         p = string;
81         while(isdigit(*p)) {
82                 p++;
83         }
84         run = p - string;
85         mode = Split_identifyMode(p, hint);
86         if(mode == QR_MODE_8) {
87                 dif = QRinput_estimateBitsModeNum(run) + 4 + ln
88                         + QRinput_estimateBitsMode8(1) /* + 4 + l8 */
89                         - QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */;
90                 if(dif > 0) {
91                         return Split_eat8(string, input, hint);
92                 }
93         }
94         if(mode == QR_MODE_AN) {
95                 dif = QRinput_estimateBitsModeNum(run) + 4 + ln
96                         + QRinput_estimateBitsModeAn(1) /* + 4 + la */
97                         - QRinput_estimateBitsModeAn(run + 1) /* - 4 - la */;
98                 if(dif > 0) {
99                         return Split_eatAn(string, input, hint);
100                 }
101         }
102
103         ret = QRinput_append(input, QR_MODE_NUM, run, (unsigned char *)string);
104         if(ret < 0) return -1;
105
106         return run;
107 }
108
109 static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint)
110 {
111         const char *p, *q;
112         int ret;
113         int run;
114         int dif;
115         int la, ln;
116
117         la = QRspec_lengthIndicator(QR_MODE_AN, input->version);
118         ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
119
120         p = string;
121         while(isalnum(*p)) {
122                 if(isdigit(*p)) {
123                         q = p;
124                         while(isdigit(*q)) {
125                                 q++;
126                         }
127                         dif = QRinput_estimateBitsModeAn(p - string) /* + 4 + la */
128                                 + QRinput_estimateBitsModeNum(q - p) + 4 + ln
129                                 - QRinput_estimateBitsModeAn(q - string) /* - 4 - la */;
130                         if(dif < 0) {
131                                 break;
132                         } else {
133                                 p = q;
134                         }
135                 } else {
136                         p++;
137                 }
138         }
139
140         run = p - string;
141
142         if(*p && !isalnum(*p)) {
143                 dif = QRinput_estimateBitsModeAn(run) + 4 + la
144                         + QRinput_estimateBitsMode8(1) /* + 4 + l8 */
145                         - QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */;
146                 if(dif > 0) {
147                         return Split_eat8(string, input, hint);
148                 }
149         }
150
151         ret = QRinput_append(input, QR_MODE_AN, run, (unsigned char *)string);
152         if(ret < 0) return -1;
153
154         return run;
155 }
156
157 static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint)
158 {
159         const char *p;
160         int ret;
161         int run;
162
163         p = string;
164         while(Split_identifyMode(p, hint) == QR_MODE_KANJI) {
165                 p += 2;
166         }
167         run = p - string;
168         ret = QRinput_append(input, QR_MODE_KANJI, run, (unsigned char *)string);
169         if(ret < 0) return -1;
170
171         return run;
172 }
173
174 static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint)
175 {
176         const char *p, *q;
177         QRencodeMode mode;
178         int ret;
179         int run;
180         int dif;
181         int la, ln;
182
183         la = QRspec_lengthIndicator(QR_MODE_AN, input->version);
184         ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
185
186         p = string + 1;
187         while(*p != '\0') {
188                 mode = Split_identifyMode(p, hint);
189                 if(mode == QR_MODE_KANJI) {
190                         break;
191                 }
192                 if(mode == QR_MODE_NUM) {
193                         q = p;
194                         while(isdigit(*q)) {
195                                 q++;
196                         }
197                         dif = QRinput_estimateBitsMode8(p - string) /* + 4 + l8 */
198                                 + QRinput_estimateBitsModeNum(q - p) + 4 + ln
199                                 - QRinput_estimateBitsMode8(q - string) /* - 4 - l8 */;
200                         if(dif < 0) {
201                                 break;
202                         } else {
203                                 p = q;
204                         }
205                 } else if(mode == QR_MODE_AN) {
206                         q = p;
207                         while(isalnum(*q)) {
208                                 q++;
209                         }
210                         dif = QRinput_estimateBitsMode8(p - string) /* + 4 + l8 */
211                                 + QRinput_estimateBitsModeAn(q - p) + 4 + la
212                                 - QRinput_estimateBitsMode8(q - string) /* - 4 - l8 */;
213                         if(dif < 0) {
214                                 break;
215                         } else {
216                                 p = q;
217                         }
218                 } else {
219                         p++;
220                 }
221         }
222
223         run = p - string;
224         ret = QRinput_append(input, QR_MODE_8, run, (unsigned char *)string);
225         if(ret < 0) return -1;
226
227         return run;
228 }
229
230 static int Split_splitString(const char *string, QRinput *input,
231                 QRencodeMode hint)
232 {
233         int length;
234         QRencodeMode mode;
235
236         if(*string == '\0') return 0;
237
238         mode = Split_identifyMode(string, hint);
239         if(mode == QR_MODE_NUM) {
240                 length = Split_eatNum(string, input, hint);
241         } else if(mode == QR_MODE_AN) {
242                 length = Split_eatAn(string, input, hint);
243         } else if(mode == QR_MODE_KANJI && hint == QR_MODE_KANJI) {
244                 length = Split_eatKanji(string, input, hint);
245         } else {
246                 length = Split_eat8(string, input, hint);
247         }
248         if(length == 0) return 0;
249         if(length < 0) return -1;
250         return Split_splitString(&string[length], input, hint);
251 }
252
253 static char *dupAndToUpper(const char *str, QRencodeMode hint)
254 {
255         char *newstr, *p;
256         QRencodeMode mode;
257
258         newstr = strdup(str);
259         if(newstr == NULL) return NULL;
260
261         p = newstr;
262         while(*p != '\0') {
263                 mode = Split_identifyMode(p, hint);
264                 if(mode == QR_MODE_KANJI) {
265                         p += 2;
266                 } else {
267                         if (*p >= 'a' && *p <= 'z') {
268                                 *p = (char)((int)*p - 32);
269                         }
270                         p++;
271                 }
272         }
273
274         return newstr;
275 }
276
277 int Split_splitStringToQRinput(const char *string, QRinput *input,
278                 QRencodeMode hint, int casesensitive)
279 {
280         char *newstr;
281         int ret;
282
283         if(string == NULL || *string == '\0') {
284                 errno = EINVAL;
285                 return -1;
286         }
287         if(!casesensitive) {
288                 newstr = dupAndToUpper(string, hint);
289                 if(newstr == NULL) return -1;
290                 ret = Split_splitString(newstr, input, hint);
291                 free(newstr);
292         } else {
293                 ret = Split_splitString(string, input, hint);
294         }
295
296         return ret;
297 }