1 #include <stdio.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include <SDL.h>
5 #include <getopt.h>
6 #include <errno.h>
7 #include "../config.h"
8 #include "../qrspec.h"
9 #include "../qrinput.h"
10 #include "../split.h"
inputTest(QRinput_List * list,const char * fmt,...)11 #include "../qrencode_inner.h"
12 
13 static SDL_Surface *screen = NULL;
14 static int casesensitive = 1;
15 static int eightbit = 0;
16 static int version = 1;
17 static int size = 4;
18 static int margin = 4;
19 static int structured = 0;
20 static int micro = 0;
21 static QRecLevel level = QR_ECLEVEL_L;
22 static QRencodeMode hint = QR_MODE_8;
23 
24 static char **textv;
25 static int textc;
26 
27 static const struct option options[] = {
28 	{"help"         , no_argument      , NULL, 'h'},
29 	{"level"        , required_argument, NULL, 'l'},
30 	{"size"         , required_argument, NULL, 's'},
31 	{"symversion"   , required_argument, NULL, 'v'},
32 	{"margin"       , required_argument, NULL, 'm'},
33 	{"structured"   , no_argument      , NULL, 'S'},
34 	{"kanji"        , no_argument      , NULL, 'k'},
35 	{"casesensitive", no_argument      , NULL, 'c'},
36 	{"ignorecase"   , no_argument      , NULL, 'i'},
37 	{"8bit"         , no_argument      , NULL, '8'},
38 	{"micro"        , no_argument      , NULL, 'M'},
39 	{"version"      , no_argument      , NULL, 'V'},
40 	{NULL, 0, NULL, 0}
41 };
42 
43 static char *optstring = "hl:s:v:m:Skci8MV";
44 
45 static char levelChar[4] = {'L', 'M', 'Q', 'H'};
46 static void usage(int help, int longopt)
47 {
48 	fprintf(stderr,
49 "view_qrcode version %s\n"
50 "Copyright (C) 2008, 2009, 2010 Kentaro Fukuchi\n", VERSION);
51 	if(help) {
52 		if(longopt) {
53 			fprintf(stderr,
54 "Usage: view_qrcode [OPTION]... [STRING]\n"
55 "Encode input data in a QR Code and display.\n\n"
56 "  -h, --help   display the help message. -h displays only the help of short\n"
57 "               options.\n\n"
58 "  -s NUMBER, --size=NUMBER\n"
59 "               specify module size in dots (pixels). (default=3)\n\n"
60 "  -l {LMQH}, --level={LMQH}\n"
61 "               specify error correction level from L (lowest) to H (highest).\n"
62 "               (default=L)\n\n"
63 "  -v NUMBER, --symversion=NUMBER\n"
64 "               specify the version of the symbol. (default=auto)\n\n"
inputSize(QRinput * input)65 "  -m NUMBER, --margin=NUMBER\n"
66 "               specify the width of the margins. (default=4)\n\n"
67 "  -S, --structured\n"
68 "               make structured symbols. Version must be specified.\n\n"
69 "  -k, --kanji  assume that the input text contains kanji (shift-jis).\n\n"
70 "  -c, --casesensitive\n"
71 "               encode lower-case alphabet characters in 8-bit mode. (default)\n\n"
72 "  -i, --ignorecase\n"
73 "               ignore case distinctions and use only upper-case characters.\n\n"
74 "  -8, --8bit   encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n\n"
75 "  -M, --micro  encode in a Micro QR Code. (experimental)\n\n"
76 "  -V, --version\n"
77 "               display the version number and copyrights of the qrencode.\n\n"
78 "  [STRING]     input data. If it is not specified, data will be taken from\n"
79 "               standard input.\n"
80 			);
81 		} else {
82 			fprintf(stderr,
83 "Usage: view_qrcode [OPTION]... [STRING]\n"
84 "Encode input data in a QR Code and display.\n\n"
85 "  -h           display this message.\n"
86 "  --help       display the usage of long options.\n"
87 "  -s NUMBER    specify module size in dots (pixels). (default=3)\n"
88 "  -l {LMQH}    specify error correction level from L (lowest) to H (highest).\n"
89 "               (default=L)\n"
90 "  -v NUMBER    specify the version of the symbol. (default=auto)\n"
test_split2(void)91 "  -m NUMBER    specify the width of the margins. (default=4)\n"
92 "  -S           make structured symbols. Version must be specified.\n"
93 "  -k           assume that the input text contains kanji (shift-jis).\n"
94 "  -c           encode lower-case alphabet characters in 8-bit mode. (default)\n"
95 "  -i           ignore case distinctions and use only upper-case characters.\n"
96 "  -8           encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n"
97 "  -M           encode in a Micro QR Code.\n"
98 "  -V           display the version number and copyrights of the qrencode.\n"
99 "  [STRING]     input data. If it is not specified, data will be taken from\n"
100 "               standard input.\n"
101 			);
102 		}
103 	}
104 }
105 
106 #define MAX_DATA_SIZE (7090 * 16) /* from the specification */
107 static unsigned char *readStdin(int *length)
108 {
109 	unsigned char *buffer;
110 	int ret;
111 
112 	buffer = (unsigned char *)malloc(MAX_DATA_SIZE + 1);
113 	if(buffer == NULL) {
114 		fprintf(stderr, "Memory allocation failed.\n");
115 		exit(EXIT_FAILURE);
116 	}
117 
118 	ret = fread(buffer, 1, MAX_DATA_SIZE, stdin);
test_split3(void)119 	if(ret == 0) {
120 		fprintf(stderr, "No input data.\n");
121 		exit(EXIT_FAILURE);
122 	}
123 	if(feof(stdin) == 0) {
124 		fprintf(stderr, "Input data is too large.\n");
125 		exit(EXIT_FAILURE);
126 	}
127 
128 	buffer[ret] = '\0';
129 	*length = ret;
130 
131 	return buffer;
132 }
133 
134 static void draw_QRcode(QRcode *qrcode, int ox, int oy)
135 {
136 	int x, y, width;
137 	unsigned char *p;
138 	SDL_Rect rect;
139 
140 	ox += margin * size;
141 	oy += margin * size;
142 	width = qrcode->width;
143 	p = qrcode->data;
144 	for(y=0; y<width; y++) {
145 		for(x=0; x<width; x++) {
146 			rect.x = ox + x * size;
147 			rect.y = oy + y * size;
148 			rect.w = size;
149 			rect.h = size;
150 			SDL_FillRect(screen, &rect, (*p&1)?0:0xffffff);
151 			p++;
152 		}
153 	}
154 }
155 
156 void draw_singleQRcode(QRinput *stream, int mask)
157 {
158 	QRcode *qrcode;
test_split4(void)159 	int width;
160 
161 	QRinput_setVersionAndErrorCorrectionLevel(stream, version, level);
162 	if(micro) {
163 		qrcode = QRcode_encodeMaskMQR(stream, mask);
164 	} else {
165 		qrcode = QRcode_encodeMask(stream, mask);
166 	}
167 	if(qrcode == NULL) {
168 		width = (11 + margin * 2) * size;
169 		fprintf(stderr, "Input data does not fit to this setting.\n");
170 	} else {
171 		version = qrcode->version;
172 		width = (qrcode->width + margin * 2) * size;
173 	}
174 
175 	screen = SDL_SetVideoMode(width, width, 32, 0);
176 	SDL_FillRect(screen, NULL, 0xffffff);
177 	if(qrcode) {
178 		draw_QRcode(qrcode, 0, 0);
179 	}
180 	SDL_Flip(screen);
181 	QRcode_free(qrcode);
182 }
183 
184 void draw_structuredQRcode(QRinput_Struct *s)
185 {
186 	int i, w, h, n, x, y;
187 	int swidth;
188 	QRcode_List *qrcodes, *p;
189 
190 	qrcodes = QRcode_encodeInputStructured(s);
191 	if(qrcodes == NULL) return;
192 
193 	swidth = (qrcodes->code->width + margin * 2) * size;
194 	n = QRcode_List_size(qrcodes);
195 	w = (n < 4)?n:4;
196 	h = (n - 1) / 4 + 1;
197 
198 	screen = SDL_SetVideoMode(swidth * w, swidth * h, 32, 0);
199 	SDL_FillRect(screen, NULL, 0xffffff);
200 
201 	p = qrcodes;
202 	for(i=0; i<n; i++) {
203 		x = (i % 4) * swidth;
204 		y = (i / 4) * swidth;
205 		draw_QRcode(p->code, x, y);
206 		p = p->next;
207 	}
208 	SDL_Flip(screen);
209 	QRcode_List_free(qrcodes);
210 }
211 
212 void draw_structuredQRcodeFromText(int argc, char **argv)
213 {
214 	QRinput_Struct *s;
215 	QRinput *input;
216 	int i, ret;
217 
218 	s = QRinput_Struct_new();
219 	if(s == NULL) {
test_split5(void)220 		fprintf(stderr, "Failed to allocate memory.\n");
221 		exit(EXIT_FAILURE);
222 	}
223 	for(i=0; i<argc; i++) {
224 		input = QRinput_new2(version, level);
225 		if(input == NULL) {
226 			fprintf(stderr, "Failed to allocate memory.\n");
227 			exit(EXIT_FAILURE);
228 		}
229 		if(eightbit) {
230 			ret = QRinput_append(input, QR_MODE_8, strlen(argv[i]), (unsigned char *)argv[i]);
231 		} else {
232 			ret = Split_splitStringToQRinput(argv[i], input, hint, casesensitive);
233 		}
234 		if(ret < 0) {
235 			perror("Encoding the input string");
236 			exit(EXIT_FAILURE);
test_split6(void)237 		}
238 		ret = QRinput_Struct_appendInput(s, input);
239 		if(ret < 0) {
240 			perror("Encoding the input string");
241 			exit(EXIT_FAILURE);
242 		}
243 	}
244 	ret = QRinput_Struct_insertStructuredAppendHeaders(s);
245 	if(ret < 0) {
246 		fprintf(stderr, "Too many inputs.\n");
247 	}
248 
249 	draw_structuredQRcode(s);
250 	QRinput_Struct_free(s);
251 }
252 
253 void draw_structuredQRcodeFromQRinput(QRinput *stream)
254 {
test_split7(void)255 	QRinput_Struct *s;
256 
257 	QRinput_setVersion(stream, version);
258 	QRinput_setErrorCorrectionLevel(stream, level);
259 	s = QRinput_splitQRinputToStruct(stream);
260 	if(s != NULL) {
261 		draw_structuredQRcode(s);
262 		QRinput_Struct_free(s);
263 	} else {
264 		fprintf(stderr, "Input data is too large for this setting.\n");
265 	}
266 }
267 
268 void view(int mode, QRinput *input)
269 {
270 	int flag = 1;
271 	int mask = -1;
test_split8(void)272 	SDL_Event event;
273 	int loop;
274 
275 	while(flag) {
276 		if(mode) {
277 			draw_structuredQRcodeFromText(textc, textv);
278 		} else {
279 			if(structured) {
280 				draw_structuredQRcodeFromQRinput(input);
281 			} else {
282 				draw_singleQRcode(input, mask);
283 			}
284 		}
285 		if(mode || structured) {
286 			printf("Version %d, Level %c.\n", version, levelChar[level]);
287 		} else {
288 			printf("Version %d, Level %c, Mask %d.\n", version, levelChar[level], mask);
test_split3c(void)289 		}
290 		loop = 1;
291 		while(loop) {
292 			usleep(10000);
293 			while(SDL_PollEvent(&event)) {
294 				if(event.type == SDL_KEYDOWN) {
295 					switch(event.key.keysym.sym) {
296 					case SDLK_RIGHT:
297 						version++;
298 						if(version > QRSPEC_VERSION_MAX)
299 							version = QRSPEC_VERSION_MAX;
300 						loop = 0;
301 						break;
302 					case SDLK_LEFT:
303 						version--;
304 						if(version < 1)
305 							version = 1;
306 						loop = 0;
307 						break;
308 					case SDLK_UP:
309 						size++;
310 						loop = 0;
311 						break;
312 					case SDLK_DOWN:
313 						size--;
314 						if(size < 1) size = 1;
315 						loop = 0;
316 						break;
317 					case SDLK_0:
318 					case SDLK_1:
319 					case SDLK_2:
320 					case SDLK_3:
321 					case SDLK_4:
322 					case SDLK_5:
323 					case SDLK_6:
324 					case SDLK_7:
325 						if(!mode && !structured) {
326 							mask = (event.key.keysym.sym - SDLK_0);
327 							loop = 0;
328 						}
test_toupper(void)329 						break;
330 					case SDLK_8:
331 						if(!mode && !structured) {
332 							mask = -1;
333 							loop = 0;
334 						}
335 						break;
336 					case SDLK_l:
337 						level = QR_ECLEVEL_L;
338 						loop = 0;
339 						break;
340 					case SDLK_m:
341 						level = QR_ECLEVEL_M;
342 						loop = 0;
343 						break;
344 					case SDLK_h:
345 						level = QR_ECLEVEL_H;
346 						loop = 0;
347 						break;
348 					case SDLK_q:
349 						level = QR_ECLEVEL_Q;
350 						loop = 0;
351 						break;
352 					case SDLK_ESCAPE:
353 						loop = 0;
354 						flag = 0;
355 						break;
356 					default:
357 						break;
358 					}
359 				}
360 				if(event.type == SDL_QUIT) {
361 					loop = 0;
362 					flag = 0;
363 				}
364 			}
365 		}
366 	}
367 }
368 
369 void view_simple(const unsigned char *str, int length)
370 {
371 	QRinput *input;
372 	int ret;
373 
374 	if(micro) {
375 		input = QRinput_newMQR(version, level);
376 	} else {
377 		input = QRinput_new2(version, level);
378 	}
test_splitNum8(void)379 	if(input == NULL) {
380 		fprintf(stderr, "Memory allocation error.\n");
381 		exit(EXIT_FAILURE);
382 	}
383 	if(eightbit) {
384 		ret = QRinput_append(input, QR_MODE_8, length, str);
385 	} else {
386 		ret = Split_splitStringToQRinput((char *)str, input, hint, casesensitive);
387 	}
388 	if(ret < 0) {
389 		perror("Encoding the input string");
390 		exit(EXIT_FAILURE);
391 	}
392 
393 	view(0, input);
394 
395 	QRinput_free(input);
396 }
test_splitAnNAn(void)397 
398 void view_multiText(char **argv, int argc)
399 {
400 	textc = argc;
401 	textv = argv;
402 
403 	view(1, NULL);
404 }
405 
406 int main(int argc, char **argv)
407 {
408 	int opt, lindex = -1;
409 	unsigned char *intext = NULL;
410 	int length = 0;
411 
412 	while((opt = getopt_long(argc, argv, optstring, options, &lindex)) != -1) {
413 		switch(opt) {
414 			case 'h':
415 				if(lindex == 0) {
416 					usage(1, 1);
417 				} else {
418 					usage(1, 0);
419 				}
420 				exit(EXIT_SUCCESS);
421 				break;
422 			case 's':
423 				size = atoi(optarg);
424 				if(size <= 0) {
425 					fprintf(stderr, "Invalid size: %d\n", size);
426 					exit(EXIT_FAILURE);
427 				}
428 				break;
429 			case 'v':
test_splitAn8An(void)430 				version = atoi(optarg);
431 				if(version < 0) {
432 					fprintf(stderr, "Invalid version: %d\n", version);
433 					exit(EXIT_FAILURE);
434 				}
435 				break;
436 			case 'l':
437 				switch(*optarg) {
438 					case 'l':
439 					case 'L':
440 						level = QR_ECLEVEL_L;
441 						break;
442 					case 'm':
443 					case 'M':
444 						level = QR_ECLEVEL_M;
445 						break;
446 					case 'q':
447 					case 'Q':
448 						level = QR_ECLEVEL_Q;
449 						break;
450 					case 'h':
451 					case 'H':
452 						level = QR_ECLEVEL_H;
453 						break;
454 					default:
455 						fprintf(stderr, "Invalid level: %s\n", optarg);
456 						exit(EXIT_FAILURE);
457 						break;
458 				}
459 				break;
460 			case 'm':
461 				margin = atoi(optarg);
462 				if(margin < 0) {
test_split8An8(void)463 					fprintf(stderr, "Invalid margin: %d\n", margin);
464 					exit(EXIT_FAILURE);
465 				}
466 				break;
467 			case 'S':
468 				structured = 1;
469 			case 'k':
470 				hint = QR_MODE_KANJI;
471 				break;
472 			case 'c':
473 				casesensitive = 1;
474 				break;
475 			case 'i':
476 				casesensitive = 0;
477 				break;
478 			case '8':
479 				eightbit = 1;
480 				break;
481 			case 'M':
482 				micro = 1;
483 				break;
484 			case 'V':
485 				usage(0, 0);
486 				exit(EXIT_SUCCESS);
487 				break;
488 			default:
489 				fprintf(stderr, "Try `view_qrcode --help' for more information.\n");
490 				exit(EXIT_FAILURE);
491 				break;
492 		}
493 	}
494 	if(argc == 1) {
495 		usage(1, 0);
test_split8N8(void)496 		exit(EXIT_SUCCESS);
497 	}
498 
499 	if(optind < argc) {
500 		intext = (unsigned char *)argv[optind];
501 		length = strlen((char *)intext);
502 	}
503 	if(intext == NULL) {
504 		intext = readStdin(&length);
505 	}
506 
507 	if(SDL_Init(SDL_INIT_VIDEO) < 0) {
508 		fprintf(stderr, "Failed initializing SDL: %s\n", SDL_GetError());
509 		return -1;
510 	}
511 	if(structured && version < 1) {
512 		fprintf(stderr, "Version number must be greater than 0 to encode structured symbols.\n");
513 		exit(EXIT_FAILURE);
514 	}
515 	if(structured && (argc - optind > 1)) {
516 		view_multiText(argv + optind, argc - optind);
517 	} else {
518 		view_simple(intext, length);
519 	}
520 
521 	SDL_Quit();
522 
523 	return 0;
524 }
525