]> Raphaƫl G. Git Repositories - cdn/blob - vendor/phpqrcode/qrinput.php
Add ausweis generator
[cdn] / vendor / phpqrcode / qrinput.php
1 <?php
2 /*
3 * PHP QR Code encoder
4 *
5 * Input encoding class
6 *
7 * Based on libqrencode C library distributed under LGPL 2.1
8 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
9 *
10 * PHP QR Code is distributed under LGPL 3
11 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
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 3 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 define('STRUCTURE_HEADER_BITS', 20);
29 define('MAX_STRUCTURED_SYMBOLS', 16);
30
31 class QRinputItem {
32
33 public $mode;
34 public $size;
35 public $data;
36 public $bstream;
37
38 public function __construct($mode, $size, $data, $bstream = null)
39 {
40 $setData = array_slice($data, 0, $size);
41
42 if (count($setData) < $size) {
43 $setData = array_merge($setData, array_fill(0,$size-count($setData),0));
44 }
45
46 if(!QRinput::check($mode, $size, $setData)) {
47 throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData));
48 }
49
50 $this->mode = $mode;
51 $this->size = $size;
52 $this->data = $setData;
53 $this->bstream = $bstream;
54 }
55
56 //----------------------------------------------------------------------
57 public function encodeModeNum($version)
58 {
59 try {
60
61 $words = (int)($this->size / 3);
62 $bs = new QRbitstream();
63
64 $val = 0x1;
65 $bs->appendNum(4, $val);
66 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_NUM, $version), $this->size);
67
68 for($i=0; $i<$words; $i++) {
69 $val = (ord($this->data[$i*3 ]) - ord('0')) * 100;
70 $val += (ord($this->data[$i*3+1]) - ord('0')) * 10;
71 $val += (ord($this->data[$i*3+2]) - ord('0'));
72 $bs->appendNum(10, $val);
73 }
74
75 if($this->size - $words * 3 == 1) {
76 $val = ord($this->data[$words*3]) - ord('0');
77 $bs->appendNum(4, $val);
78 } else if($this->size - $words * 3 == 2) {
79 $val = (ord($this->data[$words*3 ]) - ord('0')) * 10;
80 $val += (ord($this->data[$words*3+1]) - ord('0'));
81 $bs->appendNum(7, $val);
82 }
83
84 $this->bstream = $bs;
85 return 0;
86
87 } catch (Exception $e) {
88 return -1;
89 }
90 }
91
92 //----------------------------------------------------------------------
93 public function encodeModeAn($version)
94 {
95 try {
96 $words = (int)($this->size / 2);
97 $bs = new QRbitstream();
98
99 $bs->appendNum(4, 0x02);
100 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_AN, $version), $this->size);
101
102 for($i=0; $i<$words; $i++) {
103 $val = (int)QRinput::lookAnTable(ord($this->data[$i*2 ])) * 45;
104 $val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1]));
105
106 $bs->appendNum(11, $val);
107 }
108
109 if($this->size & 1) {
110 $val = QRinput::lookAnTable(ord($this->data[$words * 2]));
111 $bs->appendNum(6, $val);
112 }
113
114 $this->bstream = $bs;
115 return 0;
116
117 } catch (Exception $e) {
118 return -1;
119 }
120 }
121
122 //----------------------------------------------------------------------
123 public function encodeMode8($version)
124 {
125 try {
126 $bs = new QRbitstream();
127
128 $bs->appendNum(4, 0x4);
129 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_8, $version), $this->size);
130
131 for($i=0; $i<$this->size; $i++) {
132 $bs->appendNum(8, ord($this->data[$i]));
133 }
134
135 $this->bstream = $bs;
136 return 0;
137
138 } catch (Exception $e) {
139 return -1;
140 }
141 }
142
143 //----------------------------------------------------------------------
144 public function encodeModeKanji($version)
145 {
146 try {
147
148 $bs = new QRbitrtream();
149
150 $bs->appendNum(4, 0x8);
151 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_KANJI, $version), (int)($this->size / 2));
152
153 for($i=0; $i<$this->size; $i+=2) {
154 $val = (ord($this->data[$i]) << 8) | ord($this->data[$i+1]);
155 if($val <= 0x9ffc) {
156 $val -= 0x8140;
157 } else {
158 $val -= 0xc140;
159 }
160
161 $h = ($val >> 8) * 0xc0;
162 $val = ($val & 0xff) + $h;
163
164 $bs->appendNum(13, $val);
165 }
166
167 $this->bstream = $bs;
168 return 0;
169
170 } catch (Exception $e) {
171 return -1;
172 }
173 }
174
175 //----------------------------------------------------------------------
176 public function encodeModeStructure()
177 {
178 try {
179 $bs = new QRbitstream();
180
181 $bs->appendNum(4, 0x03);
182 $bs->appendNum(4, ord($this->data[1]) - 1);
183 $bs->appendNum(4, ord($this->data[0]) - 1);
184 $bs->appendNum(8, ord($this->data[2]));
185
186 $this->bstream = $bs;
187 return 0;
188
189 } catch (Exception $e) {
190 return -1;
191 }
192 }
193
194 //----------------------------------------------------------------------
195 public function estimateBitStreamSizeOfEntry($version)
196 {
197 $bits = 0;
198
199 if($version == 0)
200 $version = 1;
201
202 switch($this->mode) {
203 case QR_MODE_NUM: $bits = QRinput::estimateBitsModeNum($this->size); break;
204 case QR_MODE_AN: $bits = QRinput::estimateBitsModeAn($this->size); break;
205 case QR_MODE_8: $bits = QRinput::estimateBitsMode8($this->size); break;
206 case QR_MODE_KANJI: $bits = QRinput::estimateBitsModeKanji($this->size);break;
207 case QR_MODE_STRUCTURE: return STRUCTURE_HEADER_BITS;
208 default:
209 return 0;
210 }
211
212 $l = QRspec::lengthIndicator($this->mode, $version);
213 $m = 1 << $l;
214 $num = (int)(($this->size + $m - 1) / $m);
215
216 $bits += $num * (4 + $l);
217
218 return $bits;
219 }
220
221 //----------------------------------------------------------------------
222 public function encodeBitStream($version)
223 {
224 try {
225
226 unset($this->bstream);
227 $words = QRspec::maximumWords($this->mode, $version);
228
229 if($this->size > $words) {
230
231 $st1 = new QRinputItem($this->mode, $words, $this->data);
232 $st2 = new QRinputItem($this->mode, $this->size - $words, array_slice($this->data, $words));
233
234 $st1->encodeBitStream($version);
235 $st2->encodeBitStream($version);
236
237 $this->bstream = new QRbitstream();
238 $this->bstream->append($st1->bstream);
239 $this->bstream->append($st2->bstream);
240
241 unset($st1);
242 unset($st2);
243
244 } else {
245
246 $ret = 0;
247
248 switch($this->mode) {
249 case QR_MODE_NUM: $ret = $this->encodeModeNum($version); break;
250 case QR_MODE_AN: $ret = $this->encodeModeAn($version); break;
251 case QR_MODE_8: $ret = $this->encodeMode8($version); break;
252 case QR_MODE_KANJI: $ret = $this->encodeModeKanji($version);break;
253 case QR_MODE_STRUCTURE: $ret = $this->encodeModeStructure(); break;
254
255 default:
256 break;
257 }
258
259 if($ret < 0)
260 return -1;
261 }
262
263 return $this->bstream->size();
264
265 } catch (Exception $e) {
266 return -1;
267 }
268 }
269 };
270
271 //##########################################################################
272
273 class QRinput {
274
275 public $items;
276
277 private $version;
278 private $level;
279
280 //----------------------------------------------------------------------
281 public function __construct($version = 0, $level = QR_ECLEVEL_L)
282 {
283 if ($version < 0 || $version > QRSPEC_VERSION_MAX || $level > QR_ECLEVEL_H) {
284 throw new Exception('Invalid version no');
285 }
286
287 $this->version = $version;
288 $this->level = $level;
289 }
290
291 //----------------------------------------------------------------------
292 public function getVersion()
293 {
294 return $this->version;
295 }
296
297 //----------------------------------------------------------------------
298 public function setVersion($version)
299 {
300 if($version < 0 || $version > QRSPEC_VERSION_MAX) {
301 throw new Exception('Invalid version no');
302 return -1;
303 }
304
305 $this->version = $version;
306
307 return 0;
308 }
309
310 //----------------------------------------------------------------------
311 public function getErrorCorrectionLevel()
312 {
313 return $this->level;
314 }
315
316 //----------------------------------------------------------------------
317 public function setErrorCorrectionLevel($level)
318 {
319 if($level > QR_ECLEVEL_H) {
320 throw new Exception('Invalid ECLEVEL');
321 return -1;
322 }
323
324 $this->level = $level;
325
326 return 0;
327 }
328
329 //----------------------------------------------------------------------
330 public function appendEntry(QRinputItem $entry)
331 {
332 $this->items[] = $entry;
333 }
334
335 //----------------------------------------------------------------------
336 public function append($mode, $size, $data)
337 {
338 try {
339 $entry = new QRinputItem($mode, $size, $data);
340 $this->items[] = $entry;
341 return 0;
342 } catch (Exception $e) {
343 return -1;
344 }
345 }
346
347 //----------------------------------------------------------------------
348
349 public function insertStructuredAppendHeader($size, $index, $parity)
350 {
351 if( $size > MAX_STRUCTURED_SYMBOLS ) {
352 throw new Exception('insertStructuredAppendHeader wrong size');
353 }
354
355 if( $index <= 0 || $index > MAX_STRUCTURED_SYMBOLS ) {
356 throw new Exception('insertStructuredAppendHeader wrong index');
357 }
358
359 $buf = array($size, $index, $parity);
360
361 try {
362 $entry = new QRinputItem(QR_MODE_STRUCTURE, 3, buf);
363 array_unshift($this->items, $entry);
364 return 0;
365 } catch (Exception $e) {
366 return -1;
367 }
368 }
369
370 //----------------------------------------------------------------------
371 public function calcParity()
372 {
373 $parity = 0;
374
375 foreach($this->items as $item) {
376 if($item->mode != QR_MODE_STRUCTURE) {
377 for($i=$item->size-1; $i>=0; $i--) {
378 $parity ^= $item->data[$i];
379 }
380 }
381 }
382
383 return $parity;
384 }
385
386 //----------------------------------------------------------------------
387 public static function checkModeNum($size, $data)
388 {
389 for($i=0; $i<$size; $i++) {
390 if((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))){
391 return false;
392 }
393 }
394
395 return true;
396 }
397
398 //----------------------------------------------------------------------
399 public static function estimateBitsModeNum($size)
400 {
401 $w = (int)$size / 3;
402 $bits = $w * 10;
403
404 switch($size - $w * 3) {
405 case 1:
406 $bits += 4;
407 break;
408 case 2:
409 $bits += 7;
410 break;
411 default:
412 break;
413 }
414
415 return $bits;
416 }
417
418 //----------------------------------------------------------------------
419 public static $anTable = array(
420 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
421 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
422 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,
423 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1,
424 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
425 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
426 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
427 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
428 );
429
430 //----------------------------------------------------------------------
431 public static function lookAnTable($c)
432 {
433 return (($c > 127)?-1:self::$anTable[$c]);
434 }
435
436 //----------------------------------------------------------------------
437 public static function checkModeAn($size, $data)
438 {
439 for($i=0; $i<$size; $i++) {
440 if (self::lookAnTable(ord($data[$i])) == -1) {
441 return false;
442 }
443 }
444
445 return true;
446 }
447
448 //----------------------------------------------------------------------
449 public static function estimateBitsModeAn($size)
450 {
451 $w = (int)($size / 2);
452 $bits = $w * 11;
453
454 if($size & 1) {
455 $bits += 6;
456 }
457
458 return $bits;
459 }
460
461 //----------------------------------------------------------------------
462 public static function estimateBitsMode8($size)
463 {
464 return $size * 8;
465 }
466
467 //----------------------------------------------------------------------
468 public function estimateBitsModeKanji($size)
469 {
470 return (int)(($size / 2) * 13);
471 }
472
473 //----------------------------------------------------------------------
474 public static function checkModeKanji($size, $data)
475 {
476 if($size & 1)
477 return false;
478
479 for($i=0; $i<$size; $i+=2) {
480 $val = (ord($data[$i]) << 8) | ord($data[$i+1]);
481 if( $val < 0x8140
482 || ($val > 0x9ffc && $val < 0xe040)
483 || $val > 0xebbf) {
484 return false;
485 }
486 }
487
488 return true;
489 }
490
491 /***********************************************************************
492 * Validation
493 **********************************************************************/
494
495 public static function check($mode, $size, $data)
496 {
497 if($size <= 0)
498 return false;
499
500 switch($mode) {
501 case QR_MODE_NUM: return self::checkModeNum($size, $data); break;
502 case QR_MODE_AN: return self::checkModeAn($size, $data); break;
503 case QR_MODE_KANJI: return self::checkModeKanji($size, $data); break;
504 case QR_MODE_8: return true; break;
505 case QR_MODE_STRUCTURE: return true; break;
506
507 default:
508 break;
509 }
510
511 return false;
512 }
513
514
515 //----------------------------------------------------------------------
516 public function estimateBitStreamSize($version)
517 {
518 $bits = 0;
519
520 foreach($this->items as $item) {
521 $bits += $item->estimateBitStreamSizeOfEntry($version);
522 }
523
524 return $bits;
525 }
526
527 //----------------------------------------------------------------------
528 public function estimateVersion()
529 {
530 $version = 0;
531 $prev = 0;
532 do {
533 $prev = $version;
534 $bits = $this->estimateBitStreamSize($prev);
535 $version = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
536 if ($version < 0) {
537 return -1;
538 }
539 } while ($version > $prev);
540
541 return $version;
542 }
543
544 //----------------------------------------------------------------------
545 public static function lengthOfCode($mode, $version, $bits)
546 {
547 $payload = $bits - 4 - QRspec::lengthIndicator($mode, $version);
548 switch($mode) {
549 case QR_MODE_NUM:
550 $chunks = (int)($payload / 10);
551 $remain = $payload - $chunks * 10;
552 $size = $chunks * 3;
553 if($remain >= 7) {
554 $size += 2;
555 } else if($remain >= 4) {
556 $size += 1;
557 }
558 break;
559 case QR_MODE_AN:
560 $chunks = (int)($payload / 11);
561 $remain = $payload - $chunks * 11;
562 $size = $chunks * 2;
563 if($remain >= 6)
564 $size++;
565 break;
566 case QR_MODE_8:
567 $size = (int)($payload / 8);
568 break;
569 case QR_MODE_KANJI:
570 $size = (int)(($payload / 13) * 2);
571 break;
572 case QR_MODE_STRUCTURE:
573 $size = (int)($payload / 8);
574 break;
575 default:
576 $size = 0;
577 break;
578 }
579
580 $maxsize = QRspec::maximumWords($mode, $version);
581 if($size < 0) $size = 0;
582 if($size > $maxsize) $size = $maxsize;
583
584 return $size;
585 }
586
587 //----------------------------------------------------------------------
588 public function createBitStream()
589 {
590 $total = 0;
591
592 foreach($this->items as $item) {
593 $bits = $item->encodeBitStream($this->version);
594
595 if($bits < 0)
596 return -1;
597
598 $total += $bits;
599 }
600
601 return $total;
602 }
603
604 //----------------------------------------------------------------------
605 public function convertData()
606 {
607 $ver = $this->estimateVersion();
608 if($ver > $this->getVersion()) {
609 $this->setVersion($ver);
610 }
611
612 for(;;) {
613 $bits = $this->createBitStream();
614
615 if($bits < 0)
616 return -1;
617
618 $ver = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
619 if($ver < 0) {
620 throw new Exception('WRONG VERSION');
621 } else if($ver > $this->getVersion()) {
622 $this->setVersion($ver);
623 } else {
624 break;
625 }
626 }
627
628 return 0;
629 }
630
631 //----------------------------------------------------------------------
632 public function appendPaddingBit(&$bstream)
633 {
634 $bits = $bstream->size();
635 $maxwords = QRspec::getDataLength($this->version, $this->level);
636 $maxbits = $maxwords * 8;
637
638 if ($maxbits == $bits) {
639 return 0;
640 }
641
642 if ($maxbits - $bits < 5) {
643 return $bstream->appendNum($maxbits - $bits, 0);
644 }
645
646 $bits += 4;
647 $words = (int)(($bits + 7) / 8);
648
649 $padding = new QRbitstream();
650 $ret = $padding->appendNum($words * 8 - $bits + 4, 0);
651
652 if($ret < 0)
653 return $ret;
654
655 $padlen = $maxwords - $words;
656
657 if($padlen > 0) {
658
659 $padbuf = array();
660 for($i=0; $i<$padlen; $i++) {
661 $padbuf[$i] = ($i&1)?0x11:0xec;
662 }
663
664 $ret = $padding->appendBytes($padlen, $padbuf);
665
666 if($ret < 0)
667 return $ret;
668
669 }
670
671 $ret = $bstream->append($padding);
672
673 return $ret;
674 }
675
676 //----------------------------------------------------------------------
677 public function mergeBitStream()
678 {
679 if($this->convertData() < 0) {
680 return null;
681 }
682
683 $bstream = new QRbitstream();
684
685 foreach($this->items as $item) {
686 $ret = $bstream->append($item->bstream);
687 if($ret < 0) {
688 return null;
689 }
690 }
691
692 return $bstream;
693 }
694
695 //----------------------------------------------------------------------
696 public function getBitStream()
697 {
698
699 $bstream = $this->mergeBitStream();
700
701 if($bstream == null) {
702 return null;
703 }
704
705 $ret = $this->appendPaddingBit($bstream);
706 if($ret < 0) {
707 return null;
708 }
709
710 return $bstream;
711 }
712
713 //----------------------------------------------------------------------
714 public function getByteStream()
715 {
716 $bstream = $this->getBitStream();
717 if($bstream == null) {
718 return null;
719 }
720
721 return $bstream->toByte();
722 }
723 }
724
725
726