1<?php
2//============================================================+
3// File name   : qrcode.php
4// Begin       : 2010-03-22
5// Last Update : 2010-03-29
6// Version     : 1.0.002
7// License     : GNU LGPL v.3 (http://www.gnu.org/copyleft/lesser.html)
8// 	----------------------------------------------------------------------------
9//
10// 	This library is free software; you can redistribute it and/or
11// 	modify it under the terms of the GNU Lesser General Public
12// 	License as published by the Free Software Foundation; either
13// 	version 3 of the License, or any later version.
14//
15// 	This library is distributed in the hope that it will be useful,
16// 	but WITHOUT ANY WARRANTY; without even the implied warranty of
17// 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18// 	Lesser General Public License for more details.
19//
20// 	You should have received a copy of the GNU Lesser General Public
21// 	License along with this library; if not, write to the Free Software
22// 	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23//  or browse http://www.gnu.org/copyleft/lesser.html
24//
25//  ----------------------------------------------------------------------------
26//
27// DESCRIPTION :
28//
29// Class to create QR-code arrays for TCPDF class.
30// QR Code symbol is a 2D barcode that can be scanned by
31// handy terminals such as a mobile phone with CCD.
32// The capacity of QR Code is up to 7000 digits or 4000
33// characters, and has high robustness.
34// This class supports QR Code model 2, described in
35// JIS (Japanese Industrial Standards) X0510:2004
36// or ISO/IEC 18004.
37// Currently the following features are not supported:
38// ECI and FNC1 mode, Micro QR Code, QR Code model 1,
39// Structured mode.
40//
41// This class is derived from the following projects:
42// ---------------------------------------------------------
43// "PHP QR Code encoder"
44// License: GNU-LGPLv3
45// Copyright (C) 2010 by Dominik Dzienia <deltalab at poczta dot fm>
46// http://phpqrcode.sourceforge.net/
47// https://sourceforge.net/projects/phpqrcode/
48//
49// The "PHP QR Code encoder" is based on
50// "C libqrencode library" (ver. 3.1.1)
51// License: GNU-LGPL 2.1
52// Copyright (C) 2006-2010 by Kentaro Fukuchi
53// http://megaui.net/fukuchi/works/qrencode/index.en.html
54//
55// Reed-Solomon code encoder is written by Phil Karn, KA9Q.
56// Copyright (C) 2002-2006 Phil Karn, KA9Q
57//
58// QR Code is registered trademark of DENSO WAVE INCORPORATED
59// http://www.denso-wave.com/qrcode/index-e.html
60// ---------------------------------------------------------
61//
62// Author: Nicola Asuni
63//
64// (c) Copyright 2010:
65//               Nicola Asuni
66//               Tecnick.com S.r.l.
67//               Via della Pace, 11
68//               09044 Quartucciu (CA)
69//               ITALY
70//               www.tecnick.com
71//               info@tecnick.com
72//============================================================+
73
74/**
75 * Class to create QR-code arrays for TCPDF class.
76 * QR Code symbol is a 2D barcode that can be scanned by handy terminals such as a mobile phone with CCD.
77 * The capacity of QR Code is up to 7000 digits or 4000 characters, and has high robustness.
78 * This class supports QR Code model 2, described in JIS (Japanese Industrial Standards) X0510:2004 or ISO/IEC 18004.
79 * Currently the following features are not supported: ECI and FNC1 mode, Micro QR Code, QR Code model 1, Structured mode.
80 *
81 * This class is derived from "PHP QR Code encoder" by Dominik Dzienia (http://phpqrcode.sourceforge.net/) based on "libqrencode C library 3.1.1." by Kentaro Fukuchi (http://megaui.net/fukuchi/works/qrencode/index.en.html), contains Reed-Solomon code written by Phil Karn, KA9Q. QR Code is registered trademark of DENSO WAVE INCORPORATED (http://www.denso-wave.com/qrcode/index-e.html).
82 * Please read comments on this class source file for full copyright and license information.
83 *
84 * @package com.tecnick.tcpdf
85 * @abstract Class for generating QR-code array for TCPDF.
86 * @author Nicola Asuni
87 * @copyright 2010 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com
88 * @link http://www.tcpdf.org
89 * @license http://www.gnu.org/copyleft/lesser.html LGPL
90 * @version 1.0.002
91 */
92
93// definitions
94if (!defined('QRCODEDEFS')) {
95
96	/**
97	 * Indicate that definitions for this class are set
98	 */
99	define('QRCODEDEFS', true);
100
101	// -----------------------------------------------------
102
103	// Encoding modes (characters which can be encoded in QRcode)
104
105	/**
106	 * Encoding mode
107	 */
108	define('QR_MODE_NL', -1);
109
110	/**
111	 * Encoding mode numeric (0-9). 3 characters are encoded to 10bit length. In theory, 7089 characters or less can be stored in a QRcode.
112	 */
113	define('QR_MODE_NM', 0);
114
115	/**
116	 * Encoding mode alphanumeric (0-9A-Z $%*+-./:) 45characters. 2 characters are encoded to 11bit length. In theory, 4296 characters or less can be stored in a QRcode.
117	 */
118	define('QR_MODE_AN', 1);
119
120	/**
121	 * Encoding mode 8bit byte data. In theory, 2953 characters or less can be stored in a QRcode.
122	 */
123	define('QR_MODE_8B', 2);
124
125	/**
126	 * Encoding mode KANJI. A KANJI character (multibyte character) is encoded to 13bit length. In theory, 1817 characters or less can be stored in a QRcode.
127	 */
128	define('QR_MODE_KJ', 3);
129
130	/**
131	 * Encoding mode STRUCTURED (currently unsupported)
132	 */
133	define('QR_MODE_ST', 4);
134
135	// -----------------------------------------------------
136
137	// Levels of error correction.
138	// QRcode has a function of an error correcting for miss reading that white is black.
139	// Error correcting is defined in 4 level as below.
140
141	/**
142	 * Error correction level L : About 7% or less errors can be corrected.
143	 */
144	define('QR_ECLEVEL_L', 0);
145
146	/**
147	 * Error correction level M : About 15% or less errors can be corrected.
148	 */
149	define('QR_ECLEVEL_M', 1);
150
151	/**
152	 * Error correction level Q : About 25% or less errors can be corrected.
153	 */
154	define('QR_ECLEVEL_Q', 2);
155
156	/**
157	 * Error correction level H : About 30% or less errors can be corrected.
158	 */
159	define('QR_ECLEVEL_H', 3);
160
161	// -----------------------------------------------------
162
163	// Version. Size of QRcode is defined as version.
164	// Version is from 1 to 40.
165	// Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases.
166	// So version 40 is 177*177 matrix.
167
168	/**
169	 * Maximum QR Code version.
170	 */
171	define('QRSPEC_VERSION_MAX', 40);
172
173	/**
174	 * Maximum matrix size for maximum version (version 40 is 177*177 matrix).
175	 */
176    define('QRSPEC_WIDTH_MAX', 177);
177
178	// -----------------------------------------------------
179
180	/**
181	 * Matrix index to get width from $capacity array.
182	 */
183    define('QRCAP_WIDTH',    0);
184
185    /**
186	 * Matrix index to get number of words from $capacity array.
187	 */
188    define('QRCAP_WORDS',    1);
189
190    /**
191	 * Matrix index to get remainder from $capacity array.
192	 */
193    define('QRCAP_REMINDER', 2);
194
195    /**
196	 * Matrix index to get error correction level from $capacity array.
197	 */
198    define('QRCAP_EC',       3);
199
200	// -----------------------------------------------------
201
202	// Structure (currently usupported)
203
204	/**
205	 * Number of header bits for structured mode
206	 */
207    define('STRUCTURE_HEADER_BITS',  20);
208
209    /**
210	 * Max number of symbols for structured mode
211	 */
212    define('MAX_STRUCTURED_SYMBOLS', 16);
213
214	// -----------------------------------------------------
215
216    // Masks
217
218    /**
219	 * Down point base value for case 1 mask pattern (concatenation of same color in a line or a column)
220	 */
221    define('N1',  3);
222
223    /**
224	 * Down point base value for case 2 mask pattern (module block of same color)
225	 */
226	define('N2',  3);
227
228    /**
229	 * Down point base value for case 3 mask pattern (1:1:3:1:1(dark:bright:dark:bright:dark)pattern in a line or a column)
230	 */
231	define('N3', 40);
232
233    /**
234	 * Down point base value for case 4 mask pattern (ration of dark modules in whole)
235	 */
236	define('N4', 10);
237
238	// -----------------------------------------------------
239
240	// Optimization settings
241
242	/**
243	 * if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
244	 */
245	define('QR_FIND_BEST_MASK', true);
246
247	/**
248	 * if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
249	 */
250	define('QR_FIND_FROM_RANDOM', 2);
251
252	/**
253	 * when QR_FIND_BEST_MASK === false
254	 */
255	define('QR_DEFAULT_MASK', 2);
256
257	// -----------------------------------------------------
258
259} // end of definitions
260
261// #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
262
263if (!class_exists('QRcode', false)) {
264
265	// for compaibility with PHP4
266	if (!function_exists('str_split')) {
267    	/**
268    	 * Convert a string to an array (needed for PHP4 compatibility)
269    	 * @param string $string The input string.
270    	 * @param int $split_length Maximum length of the chunk.
271    	 * @return  If the optional split_length  parameter is specified, the returned array will be broken down into chunks with each being split_length  in length, otherwise each chunk will be one character in length. FALSE is returned if split_length is less than 1. If the split_length length exceeds the length of string , the entire string is returned as the first (and only) array element.
272    	 */
273		function str_split($string, $split_length=1) {
274			if ((strlen($string) > $split_length) OR (!$split_length)) {
275				do {
276					$c = strlen($string);
277					$parts[] = substr($string, 0, $split_length);
278					$string = substr($string, $split_length);
279				} while ($string !== false);
280			} else {
281				$parts = array($string);
282			}
283			return $parts;
284		}
285	}
286
287	// #####################################################
288
289	/**
290	 * Class to create QR-code arrays for TCPDF class.
291	 * QR Code symbol is a 2D barcode that can be scanned by handy terminals such as a mobile phone with CCD.
292	 * The capacity of QR Code is up to 7000 digits or 4000 characters, and has high robustness.
293	 * This class supports QR Code model 2, described in JIS (Japanese Industrial Standards) X0510:2004 or ISO/IEC 18004.
294	 * Currently the following features are not supported: ECI and FNC1 mode, Micro QR Code, QR Code model 1, Structured mode.
295	 *
296	 * This class is derived from "PHP QR Code encoder" by Dominik Dzienia (http://phpqrcode.sourceforge.net/) based on "libqrencode C library 3.1.1." by Kentaro Fukuchi (http://megaui.net/fukuchi/works/qrencode/index.en.html), contains Reed-Solomon code written by Phil Karn, KA9Q. QR Code is registered trademark of DENSO WAVE INCORPORATED (http://www.denso-wave.com/qrcode/index-e.html).
297	 * Please read comments on this class source file for full copyright and license information.
298	 *
299	 * @name QRcode
300	 * @package com.tecnick.tcpdf
301	 * @abstract Class for generating QR-code array for TCPDF.
302	 * @author Nicola Asuni
303	 * @copyright 2010 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com
304	 * @link http://www.tcpdf.org
305	 * @license http://www.gnu.org/copyleft/lesser.html LGPL
306	 * @version 1.0.002
307	 */
308	class QRcode {
309
310		/**
311		 * @var barcode array to be returned which is readable by TCPDF
312		 * @access protected
313		 */
314		protected $barcode_array = array();
315
316		/**
317		 * @var QR code version. Size of QRcode is defined as version. Version is from 1 to 40. Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases. So version 40 is 177*177 matrix.
318		 * @access protected
319		 */
320		protected $version = 0;
321
322		/**
323		 * @var Levels of error correction. See definitions for possible values.
324		 * @access protected
325		 */
326		protected $level = QR_ECLEVEL_L;
327
328		/**
329		 * @var Encoding mode
330		 * @access protected
331		 */
332		protected $hint = QR_MODE_8B;
333
334		/**
335		 * @var if true the input string will be converted to uppercase
336		 * @access protected
337		 */
338		protected $casesensitive = true;
339
340		/**
341		 * @var structured QR code (not supported yet)
342		 * @access protected
343		 */
344		protected $structured = 0;
345
346		/**
347		 * @var mask data
348		 * @access protected
349		 */
350		protected $data;
351
352		// FrameFiller
353
354		/**
355		 * @var width
356		 * @access protected
357		 */
358		protected $width;
359
360		/**
361		 * @var frame
362		 * @access protected
363		 */
364		protected $frame;
365
366		/**
367		 * @var X position of bit
368		 * @access protected
369		 */
370		protected $x;
371
372		/**
373		 * @var Y position of bit
374		 * @access protected
375		 */
376		protected $y;
377
378		/**
379		 * @var direction
380		 * @access protected
381		 */
382		protected $dir;
383
384		/**
385		 * @var single bit
386		 * @access protected
387		 */
388		protected $bit;
389
390		// ---- QRrawcode ----
391
392		/**
393		 * @var data code
394		 * @access protected
395		 */
396		protected $datacode = array();
397
398		/**
399		 * @var error correction code
400		 * @access protected
401		 */
402		protected $ecccode = array();
403
404		/**
405		 * @var blocks
406		 * @access protected
407		 */
408		protected $blocks;
409
410		/**
411		 * @var Reed-Solomon blocks
412		 * @access protected
413		 */
414		protected $rsblocks = array(); //of RSblock
415
416		/**
417		 * @var counter
418		 * @access protected
419		 */
420		protected $count;
421
422		/**
423		 * @var data length
424		 * @access protected
425		 */
426		protected $dataLength;
427
428		/**
429		 * @var error correction length
430		 * @access protected
431		 */
432		protected $eccLength;
433
434		/**
435		 * @var b1
436		 * @access protected
437		 */
438		protected $b1;
439
440		// ---- QRmask ----
441
442		/**
443		 * @var run length
444		 * @access protected
445		 */
446		protected $runLength = array();
447
448		// ---- QRsplit ----
449
450		/**
451		 * @var input data string
452		 * @access protected
453		 */
454		protected $dataStr = '';
455
456		/**
457		 * @var input items
458		 * @access protected
459		 */
460		protected $items;
461
462		// Reed-Solomon items
463
464		/**
465		 * @var Reed-Solomon items
466		 * @access protected
467		 */
468		protected $rsitems = array();
469
470		/**
471		 * @var array of frames
472		 * @access protected
473		 */
474		protected $frames = array();
475
476		/**
477		 * @var alphabet-numeric convesion table
478		 * @access protected
479		 */
480		protected $anTable = array(
481			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
482			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
483			36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, //
484			 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 44, -1, -1, -1, -1, -1, //
485			-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //
486			25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, //
487			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
488			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  //
489			);
490
491		/**
492		 * @var array Table of the capacity of symbols
493		 * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
494		 * @access protected
495		 */
496		protected $capacity = array(
497			array(  0,    0, 0, array(   0,    0,    0,    0)), //
498			array( 21,   26, 0, array(   7,   10,   13,   17)), //  1
499			array( 25,   44, 7, array(  10,   16,   22,   28)), //
500			array( 29,   70, 7, array(  15,   26,   36,   44)), //
501			array( 33,  100, 7, array(  20,   36,   52,   64)), //
502			array( 37,  134, 7, array(  26,   48,   72,   88)), //  5
503			array( 41,  172, 7, array(  36,   64,   96,  112)), //
504			array( 45,  196, 0, array(  40,   72,  108,  130)), //
505			array( 49,  242, 0, array(  48,   88,  132,  156)), //
506			array( 53,  292, 0, array(  60,  110,  160,  192)), //
507			array( 57,  346, 0, array(  72,  130,  192,  224)), // 10
508			array( 61,  404, 0, array(  80,  150,  224,  264)), //
509			array( 65,  466, 0, array(  96,  176,  260,  308)), //
510			array( 69,  532, 0, array( 104,  198,  288,  352)), //
511			array( 73,  581, 3, array( 120,  216,  320,  384)), //
512			array( 77,  655, 3, array( 132,  240,  360,  432)), // 15
513			array( 81,  733, 3, array( 144,  280,  408,  480)), //
514			array( 85,  815, 3, array( 168,  308,  448,  532)), //
515			array( 89,  901, 3, array( 180,  338,  504,  588)), //
516			array( 93,  991, 3, array( 196,  364,  546,  650)), //
517			array( 97, 1085, 3, array( 224,  416,  600,  700)), // 20
518			array(101, 1156, 4, array( 224,  442,  644,  750)), //
519			array(105, 1258, 4, array( 252,  476,  690,  816)), //
520			array(109, 1364, 4, array( 270,  504,  750,  900)), //
521			array(113, 1474, 4, array( 300,  560,  810,  960)), //
522			array(117, 1588, 4, array( 312,  588,  870, 1050)), // 25
523			array(121, 1706, 4, array( 336,  644,  952, 1110)), //
524			array(125, 1828, 4, array( 360,  700, 1020, 1200)), //
525			array(129, 1921, 3, array( 390,  728, 1050, 1260)), //
526			array(133, 2051, 3, array( 420,  784, 1140, 1350)), //
527			array(137, 2185, 3, array( 450,  812, 1200, 1440)), // 30
528			array(141, 2323, 3, array( 480,  868, 1290, 1530)), //
529			array(145, 2465, 3, array( 510,  924, 1350, 1620)), //
530			array(149, 2611, 3, array( 540,  980, 1440, 1710)), //
531			array(153, 2761, 3, array( 570, 1036, 1530, 1800)), //
532			array(157, 2876, 0, array( 570, 1064, 1590, 1890)), // 35
533			array(161, 3034, 0, array( 600, 1120, 1680, 1980)), //
534			array(165, 3196, 0, array( 630, 1204, 1770, 2100)), //
535			array(169, 3362, 0, array( 660, 1260, 1860, 2220)), //
536			array(173, 3532, 0, array( 720, 1316, 1950, 2310)), //
537			array(177, 3706, 0, array( 750, 1372, 2040, 2430))  // 40
538		);
539
540		/**
541		 * @var array Length indicator
542		 * @access protected
543		 */
544		protected $lengthTableBits = array(
545			array(10, 12, 14),
546			array( 9, 11, 13),
547			array( 8, 16, 16),
548			array( 8, 10, 12)
549		);
550
551		/**
552		 * @var array Table of the error correction code (Reed-Solomon block)
553		 * See Table 12-16 (pp.30-36), JIS X0510:2004.
554		 * @access protected
555		 */
556		protected $eccTable = array(
557			array(array( 0,  0), array( 0,  0), array( 0,  0), array( 0,  0)), //
558			array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)), //  1
559			array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)), //
560			array(array( 1,  0), array( 1,  0), array( 2,  0), array( 2,  0)), //
561			array(array( 1,  0), array( 2,  0), array( 2,  0), array( 4,  0)), //
562			array(array( 1,  0), array( 2,  0), array( 2,  2), array( 2,  2)), //  5
563			array(array( 2,  0), array( 4,  0), array( 4,  0), array( 4,  0)), //
564			array(array( 2,  0), array( 4,  0), array( 2,  4), array( 4,  1)), //
565			array(array( 2,  0), array( 2,  2), array( 4,  2), array( 4,  2)), //
566			array(array( 2,  0), array( 3,  2), array( 4,  4), array( 4,  4)), //
567			array(array( 2,  2), array( 4,  1), array( 6,  2), array( 6,  2)), // 10
568			array(array( 4,  0), array( 1,  4), array( 4,  4), array( 3,  8)), //
569			array(array( 2,  2), array( 6,  2), array( 4,  6), array( 7,  4)), //
570			array(array( 4,  0), array( 8,  1), array( 8,  4), array(12,  4)), //
571			array(array( 3,  1), array( 4,  5), array(11,  5), array(11,  5)), //
572			array(array( 5,  1), array( 5,  5), array( 5,  7), array(11,  7)), // 15
573			array(array( 5,  1), array( 7,  3), array(15,  2), array( 3, 13)), //
574			array(array( 1,  5), array(10,  1), array( 1, 15), array( 2, 17)), //
575			array(array( 5,  1), array( 9,  4), array(17,  1), array( 2, 19)), //
576			array(array( 3,  4), array( 3, 11), array(17,  4), array( 9, 16)), //
577			array(array( 3,  5), array( 3, 13), array(15,  5), array(15, 10)), // 20
578			array(array( 4,  4), array(17,  0), array(17,  6), array(19,  6)), //
579			array(array( 2,  7), array(17,  0), array( 7, 16), array(34,  0)), //
580			array(array( 4,  5), array( 4, 14), array(11, 14), array(16, 14)), //
581			array(array( 6,  4), array( 6, 14), array(11, 16), array(30,  2)), //
582			array(array( 8,  4), array( 8, 13), array( 7, 22), array(22, 13)), // 25
583			array(array(10,  2), array(19,  4), array(28,  6), array(33,  4)), //
584			array(array( 8,  4), array(22,  3), array( 8, 26), array(12, 28)), //
585			array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)), //
586			array(array( 7,  7), array(21,  7), array( 1, 37), array(19, 26)), //
587			array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), // 30
588			array(array(13,  3), array( 2, 29), array(42,  1), array(23, 28)), //
589			array(array(17,  0), array(10, 23), array(10, 35), array(19, 35)), //
590			array(array(17,  1), array(14, 21), array(29, 19), array(11, 46)), //
591			array(array(13,  6), array(14, 23), array(44,  7), array(59,  1)), //
592			array(array(12,  7), array(12, 26), array(39, 14), array(22, 41)), // 35
593			array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)), //
594			array(array(17,  4), array(29, 14), array(49, 10), array(24, 46)), //
595			array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)), //
596			array(array(20,  4), array(40,  7), array(43, 22), array(10, 67)), //
597			array(array(19,  6), array(18, 31), array(34, 34), array(20, 61))  // 40
598		);
599
600		/**
601		 * @var array Positions of alignment patterns.
602		 * This array includes only the second and the third position of the alignment patterns. Rest of them can be calculated from the distance between them.
603		 * See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
604		 * @access protected
605		 */
606		protected $alignmentPattern = array(
607			array( 0,  0),
608			array( 0,  0), array(18,  0), array(22,  0), array(26,  0), array(30,  0), //  1- 5
609			array(34,  0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), //  6-10
610			array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), // 11-15
611			array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), // 16-20
612			array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), // 21-25
613			array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), // 26-30
614			array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), // 31-35
615			array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58)  // 35-40
616		);
617
618		/**
619		 * @var array Version information pattern (BCH coded).
620		 * See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
621		 * size: [QRSPEC_VERSION_MAX - 6]
622		 * @access protected
623		 */
624		protected $versionPattern = array(
625			0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, //
626			0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, //
627			0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, //
628			0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, //
629			0x27541, 0x28c69
630		);
631
632		/**
633		 * @var array Format information
634		 * @access protected
635		 */
636		protected $formatInfo = array(
637			array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), //
638			array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), //
639			array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), //
640			array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b)  //
641		);
642
643
644		// -------------------------------------------------
645		// -------------------------------------------------
646
647
648		/**
649		 * This is the class constructor.
650		 * Creates a QRcode object
651		 * @param string $code code to represent using QRcode
652		 * @param string $eclevel error level: <ul><li>L : About 7% or less errors can be corrected.</li><li>M : About 15% or less errors can be corrected.</li><li>Q : About 25% or less errors can be corrected.</li><li>H : About 30% or less errors can be corrected.</li></ul>
653		 * @access public
654		 * @since 1.0.000
655		 */
656		public function __construct($code, $eclevel = 'L') {
657			$barcode_array = array();
658			if ((is_null($code)) OR ($code == '\0') OR ($code == '')) {
659				return false;
660			}
661			// set error correction level
662			$this->level = array_search($eclevel, array('L', 'M', 'Q', 'H'));
663			if ($this->level === false) {
664				$this->level = QR_ECLEVEL_L;
665			}
666			if (($this->hint != QR_MODE_8B) AND ($this->hint != QR_MODE_KJ)) {
667				return false;
668			}
669			if (($this->version < 0) OR ($this->version > QRSPEC_VERSION_MAX)) {
670				return false;
671			}
672			$this->items = array();
673			$this->encodeString($code);
674			$qrTab = $this->binarize($this->data);
675			$size = count($qrTab);
676			$barcode_array['num_rows'] = $size;
677			$barcode_array['num_cols'] = $size;
678			$barcode_array['bcode'] = array();
679			foreach ($qrTab as $line) {
680				$arrAdd = array();
681				foreach (str_split($line) as $char) {
682					$arrAdd[] = ($char=='1')?1:0;
683				}
684				$barcode_array['bcode'][] = $arrAdd;
685			}
686			$this->barcode_array = $barcode_array;
687		}
688
689		/**
690		 * Returns a barcode array which is readable by TCPDF
691		 * @return array barcode array readable by TCPDF;
692		 * @access public
693		 */
694		public function getBarcodeArray() {
695			return $this->barcode_array;
696		}
697
698		/**
699		 * Convert the frame in binary form
700		 * @param array $frame array to binarize
701		 * @return array frame in binary form
702		 */
703		protected function binarize($frame) {
704			$len = count($frame);
705			// the frame is square (width = height)
706			foreach ($frame as &$frameLine) {
707				for ($i=0; $i<$len; $i++) {
708					$frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
709				}
710			}
711			return $frame;
712		}
713
714		/**
715		 * Encode the input string to QR code
716		 * @param string $string input string to encode
717		 */
718		protected function encodeString($string) {
719			$this->dataStr = $string;
720			if (!$this->casesensitive) {
721				$this->toUpper();
722			}
723			$ret = $this->splitString();
724			if ($ret < 0) {
725				return NULL;
726			}
727			$this->encodeMask(-1);
728		}
729
730		/**
731		 * Encode mask
732		 * @param int $mask masking mode
733		 */
734		protected function encodeMask($mask) {
735			$spec = array(0, 0, 0, 0, 0);
736			$this->datacode = $this->getByteStream($this->items);
737			if (is_null($this->datacode)) {
738				return NULL;
739			}
740			$spec = $this->getEccSpec($this->version, $this->level, $spec);
741			$this->b1 = $this->rsBlockNum1($spec);
742			$this->dataLength = $this->rsDataLength($spec);
743			$this->eccLength = $this->rsEccLength($spec);
744			$this->ecccode = array_fill(0, $this->eccLength, 0);
745			$this->blocks = $this->rsBlockNum($spec);
746			$ret = $this->init($spec);
747			if ($ret < 0) {
748				return NULL;
749			}
750			$this->count = 0;
751			$this->width = $this->getWidth($this->version);
752			$this->frame = $this->newFrame($this->version);
753			$this->x = $this->width - 1;
754			$this->y = $this->width - 1;
755			$this->dir = -1;
756			$this->bit = -1;
757			// inteleaved data and ecc codes
758			for ($i=0; $i < ($this->dataLength + $this->eccLength); $i++) {
759				$code = $this->getCode();
760				$bit = 0x80;
761				for ($j=0; $j<8; $j++) {
762					$addr = $this->getNextPosition();
763					$this->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
764					$bit = $bit >> 1;
765				}
766			}
767			// remainder bits
768			$j = $this->getRemainder($this->version);
769			for ($i=0; $i<$j; $i++) {
770				$addr = $this->getNextPosition();
771				$this->setFrameAt($addr, 0x02);
772			}
773			// masking
774			$this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
775			if ($mask < 0) {
776				if (QR_FIND_BEST_MASK) {
777					$masked = $this->mask($this->width, $this->frame, $this->level);
778				} else {
779					$masked = $this->makeMask($this->width, $this->frame, (intval(QR_DEFAULT_MASK) % 8), $this->level);
780				}
781			} else {
782				$masked = $this->makeMask($this->width, $this->frame, $mask, $this->level);
783			}
784			if ($masked == NULL) {
785				return NULL;
786			}
787			$this->data = $masked;
788		}
789
790		// - - - - - - - - - - - - - - - - - - - - - - - - -
791
792		// FrameFiller
793
794		/**
795		 * Set frame value at specified position
796		 * @param array $at x,y position
797		 * @param int $val value of the character to set
798		 */
799		protected function setFrameAt($at, $val) {
800			$this->frame[$at['y']][$at['x']] = chr($val);
801		}
802
803		/**
804		 * Get frame value at specified position
805		 * @param array $at x,y position
806		 * @return value at specified position
807		 */
808		protected function getFrameAt($at) {
809			return ord($this->frame[$at['y']][$at['x']]);
810		}
811
812		/**
813		 * Return the next frame position
814		 * @return array of x,y coordinates
815		 */
816		protected function getNextPosition() {
817			do {
818				if ($this->bit == -1) {
819					$this->bit = 0;
820					return array('x'=>$this->x, 'y'=>$this->y);
821				}
822				$x = $this->x;
823				$y = $this->y;
824				$w = $this->width;
825				if ($this->bit == 0) {
826					$x--;
827					$this->bit++;
828				} else {
829					$x++;
830					$y += $this->dir;
831					$this->bit--;
832				}
833				if ($this->dir < 0) {
834					if ($y < 0) {
835						$y = 0;
836						$x -= 2;
837						$this->dir = 1;
838						if ($x == 6) {
839							$x--;
840							$y = 9;
841						}
842					}
843				} else {
844					if ($y == $w) {
845						$y = $w - 1;
846						$x -= 2;
847						$this->dir = -1;
848						if ($x == 6) {
849							$x--;
850							$y -= 8;
851						}
852					}
853				}
854				if (($x < 0) OR ($y < 0)) {
855					return NULL;
856				}
857				$this->x = $x;
858				$this->y = $y;
859			} while(ord($this->frame[$y][$x]) & 0x80);
860			return array('x'=>$x, 'y'=>$y);
861		}
862
863		// - - - - - - - - - - - - - - - - - - - - - - - - -
864
865		// QRrawcode
866
867		/**
868		 * Initialize code.
869		 * @param array $spec array of ECC specification
870		 * @return 0 in case of success, -1 in case of error
871		 */
872		protected function init($spec) {
873			$dl = $this->rsDataCodes1($spec);
874			$el = $this->rsEccCodes1($spec);
875			$rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
876			$blockNo = 0;
877			$dataPos = 0;
878			$eccPos = 0;
879			$endfor = $this->rsBlockNum1($spec);
880			for ($i=0; $i < $endfor; ++$i) {
881				$ecc = array_slice($this->ecccode, $eccPos);
882				$this->rsblocks[$blockNo] = array();
883				$this->rsblocks[$blockNo]['dataLength'] = $dl;
884				$this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
885				$this->rsblocks[$blockNo]['eccLength'] = $el;
886				$ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
887				$this->rsblocks[$blockNo]['ecc'] = $ecc;
888				$this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
889				$dataPos += $dl;
890				$eccPos += $el;
891				$blockNo++;
892			}
893			if ($this->rsBlockNum2($spec) == 0) {
894				return 0;
895			}
896			$dl = $this->rsDataCodes2($spec);
897			$el = $this->rsEccCodes2($spec);
898			$rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
899			if ($rs == NULL) {
900				return -1;
901			}
902			$endfor = $this->rsBlockNum2($spec);
903			for ($i=0; $i < $endfor; ++$i) {
904				$ecc = array_slice($this->ecccode, $eccPos);
905				$this->rsblocks[$blockNo] = array();
906				$this->rsblocks[$blockNo]['dataLength'] = $dl;
907				$this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
908				$this->rsblocks[$blockNo]['eccLength'] = $el;
909				$ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
910				$this->rsblocks[$blockNo]['ecc'] = $ecc;
911				$this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
912				$dataPos += $dl;
913				$eccPos += $el;
914				$blockNo++;
915			}
916			return 0;
917		}
918
919		/**
920		 * Return Reed-Solomon block code.
921		 * @return array rsblocks
922		 */
923		protected function getCode() {
924			if ($this->count < $this->dataLength) {
925				$row = $this->count % $this->blocks;
926				$col = $this->count / $this->blocks;
927				if ($col >= $this->rsblocks[0]['dataLength']) {
928					$row += $this->b1;
929				}
930				$ret = $this->rsblocks[$row]['data'][$col];
931			} elseif ($this->count < $this->dataLength + $this->eccLength) {
932				$row = ($this->count - $this->dataLength) % $this->blocks;
933				$col = ($this->count - $this->dataLength) / $this->blocks;
934				$ret = $this->rsblocks[$row]['ecc'][$col];
935			} else {
936				return 0;
937			}
938			$this->count++;
939			return $ret;
940		}
941
942		// - - - - - - - - - - - - - - - - - - - - - - - - -
943
944		// QRmask
945
946		/**
947		 * Write Format Information on frame and returns the number of black bits
948		 * @param int $width frame width
949		 * @param array $frame frame
950		 * @param array $mask masking mode
951		 * @param int $level error correction level
952		 * @return int blacks
953		 */
954		 protected function writeFormatInformation($width, &$frame, $mask, $level) {
955			$blacks = 0;
956			$format =  $this->getFormatInfo($mask, $level);
957			for ($i=0; $i<8; ++$i) {
958				if ($format & 1) {
959					$blacks += 2;
960					$v = 0x85;
961				} else {
962					$v = 0x84;
963				}
964				$frame[8][$width - 1 - $i] = chr($v);
965				if ($i < 6) {
966					$frame[$i][8] = chr($v);
967				} else {
968					$frame[$i + 1][8] = chr($v);
969				}
970				$format = $format >> 1;
971			}
972			for ($i=0; $i<7; ++$i) {
973			if ($format & 1) {
974				$blacks += 2;
975				$v = 0x85;
976			} else {
977				$v = 0x84;
978			}
979			$frame[$width - 7 + $i][8] = chr($v);
980			if ($i == 0) {
981				$frame[8][7] = chr($v);
982			} else {
983				$frame[8][6 - $i] = chr($v);
984			}
985			$format = $format >> 1;
986			}
987			return $blacks;
988		}
989
990		/**
991		 * mask0
992		 * @param int $x X position
993		 * @param int $y Y position
994		 * @return int mask
995		 */
996		 protected function mask0($x, $y) {
997			return ($x + $y) & 1;
998		}
999
1000		/**
1001		 * mask1
1002		 * @param int $x X position
1003		 * @param int $y Y position
1004		 * @return int mask
1005		 */
1006		 protected function mask1($x, $y) {
1007			return ($y & 1);
1008		}
1009
1010		/**
1011		 * mask2
1012		 * @param int $x X position
1013		 * @param int $y Y position
1014		 * @return int mask
1015		 */
1016		 protected function mask2($x, $y) {
1017			return ($x % 3);
1018		}
1019
1020		/**
1021		 * mask3
1022		 * @param int $x X position
1023		 * @param int $y Y position
1024		 * @return int mask
1025		 */
1026		 protected function mask3($x, $y) {
1027			return ($x + $y) % 3;
1028		}
1029
1030		/**
1031		 * mask4
1032		 * @param int $x X position
1033		 * @param int $y Y position
1034		 * @return int mask
1035		 */
1036		 protected function mask4($x, $y) {
1037			return (((int)($y / 2)) + ((int)($x / 3))) & 1;
1038		}
1039
1040		/**
1041		 * mask5
1042		 * @param int $x X position
1043		 * @param int $y Y position
1044		 * @return int mask
1045		 */
1046		 protected function mask5($x, $y) {
1047			return (($x * $y) & 1) + ($x * $y) % 3;
1048		}
1049
1050		/**
1051		 * mask6
1052		 * @param int $x X position
1053		 * @param int $y Y position
1054		 * @return int mask
1055		 */
1056		 protected function mask6($x, $y) {
1057			return ((($x * $y) & 1) + ($x * $y) % 3) & 1;
1058		}
1059
1060		/**
1061		 * mask7
1062		 * @param int $x X position
1063		 * @param int $y Y position
1064		 * @return int mask
1065		 */
1066		 protected function mask7($x, $y) {
1067			return ((($x * $y) % 3) + (($x + $y) & 1)) & 1;
1068		}
1069
1070		/**
1071		 * Return bitmask
1072		 * @param int $maskNo mask number
1073		 * @param int $width width
1074		 * @param array $frame frame
1075		 * @return array bitmask
1076		 */
1077		protected function generateMaskNo($maskNo, $width, $frame) {
1078			$bitMask = array_fill(0, $width, array_fill(0, $width, 0));
1079			for ($y=0; $y<$width; ++$y) {
1080				for ($x=0; $x<$width; ++$x) {
1081					if (ord($frame[$y][$x]) & 0x80) {
1082						$bitMask[$y][$x] = 0;
1083					} else {
1084						$maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
1085						$bitMask[$y][$x] = ($maskFunc == 0)?1:0;
1086					}
1087				}
1088			}
1089			return $bitMask;
1090		}
1091
1092		/**
1093		 * makeMaskNo
1094		 * @param int $maskNo
1095		 * @param int $width
1096		 * @param int $s
1097		 * @param int $d
1098		 * @param boolean $maskGenOnly
1099		 * @return int b
1100		 */
1101		 protected function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly=false) {
1102			$b = 0;
1103			$bitMask = array();
1104			$bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
1105			if ($maskGenOnly) {
1106				return;
1107			}
1108			$d = $s;
1109			for ($y=0; $y<$width; ++$y) {
1110				for ($x=0; $x<$width; ++$x) {
1111					if ($bitMask[$y][$x] == 1) {
1112						$d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);
1113					}
1114					$b += (int)(ord($d[$y][$x]) & 1);
1115				}
1116			}
1117			return $b;
1118		}
1119
1120		/**
1121		 * makeMask
1122		 * @param int $width
1123		 * @param array $frame
1124		 * @param int $maskNo
1125		 * @param int $level
1126		 * @return array mask
1127		 */
1128		 protected function makeMask($width, $frame, $maskNo, $level) {
1129			$masked = array_fill(0, $width, str_repeat("\0", $width));
1130			$this->makeMaskNo($maskNo, $width, $frame, $masked);
1131			$this->writeFormatInformation($width, $masked, $maskNo, $level);
1132			return $masked;
1133		}
1134
1135		/**
1136		 * calcN1N3
1137		 * @param int $length
1138		 * @return int demerit
1139		 */
1140		 protected function calcN1N3($length) {
1141			$demerit = 0;
1142			for ($i=0; $i<$length; ++$i) {
1143				if ($this->runLength[$i] >= 5) {
1144					$demerit += (N1 + ($this->runLength[$i] - 5));
1145				}
1146				if ($i & 1) {
1147					if (($i >= 3) AND ($i < ($length-2)) AND ($this->runLength[$i] % 3 == 0)) {
1148						$fact = (int)($this->runLength[$i] / 3);
1149						if (($this->runLength[$i-2] == $fact)
1150							AND ($this->runLength[$i-1] == $fact)
1151							AND ($this->runLength[$i+1] == $fact)
1152							AND ($this->runLength[$i+2] == $fact)) {
1153							if (($this->runLength[$i-3] < 0) OR ($this->runLength[$i-3] >= (4 * $fact))) {
1154								$demerit += N3;
1155							} elseif ((($i+3) >= $length) OR ($this->runLength[$i+3] >= (4 * $fact))) {
1156								$demerit += N3;
1157							}
1158						}
1159					}
1160				}
1161			}
1162			return $demerit;
1163		}
1164
1165		/**
1166		 * evaluateSymbol
1167		 * @param int $width
1168		 * @param array $frame
1169		 * @return int demerit
1170		 */
1171		 protected function evaluateSymbol($width, $frame) {
1172			$head = 0;
1173			$demerit = 0;
1174			for ($y=0; $y<$width; ++$y) {
1175				$head = 0;
1176				$this->runLength[0] = 1;
1177				$frameY = $frame[$y];
1178				if ($y > 0) {
1179					$frameYM = $frame[$y-1];
1180				}
1181				for ($x=0; $x<$width; ++$x) {
1182					if (($x > 0) AND ($y > 0)) {
1183						$b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
1184						$w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
1185						if (($b22 | ($w22 ^ 1)) & 1) {
1186							$demerit += N2;
1187						}
1188					}
1189					if (($x == 0) AND (ord($frameY[$x]) & 1)) {
1190						$this->runLength[0] = -1;
1191						$head = 1;
1192						$this->runLength[$head] = 1;
1193					} elseif ($x > 0) {
1194						if ((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
1195							$head++;
1196							$this->runLength[$head] = 1;
1197						} else {
1198							$this->runLength[$head]++;
1199						}
1200					}
1201				}
1202				$demerit += $this->calcN1N3($head+1);
1203			}
1204			for ($x=0; $x<$width; ++$x) {
1205				$head = 0;
1206				$this->runLength[0] = 1;
1207				for ($y=0; $y<$width; ++$y) {
1208					if (($y == 0) AND (ord($frame[$y][$x]) & 1)) {
1209						$this->runLength[0] = -1;
1210						$head = 1;
1211						$this->runLength[$head] = 1;
1212					} elseif ($y > 0) {
1213						if ((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
1214							$head++;
1215							$this->runLength[$head] = 1;
1216						} else {
1217							$this->runLength[$head]++;
1218						}
1219					}
1220				}
1221				$demerit += $this->calcN1N3($head+1);
1222			}
1223			return $demerit;
1224		}
1225
1226		/**
1227		 * mask
1228		 * @param int $width
1229		 * @param array $frame
1230		 * @param int $level
1231		 * @return array best mask
1232		 */
1233		 protected function mask($width, $frame, $level) {
1234			$minDemerit = PHP_INT_MAX;
1235			$bestMaskNum = 0;
1236			$bestMask = array();
1237			$checked_masks = array(0, 1, 2, 3, 4, 5, 6, 7);
1238			if (QR_FIND_FROM_RANDOM !== false) {
1239				$howManuOut = 8 - (QR_FIND_FROM_RANDOM % 9);
1240				for ($i = 0; $i <  $howManuOut; ++$i) {
1241					$remPos = rand (0, count($checked_masks)-1);
1242					unset($checked_masks[$remPos]);
1243					$checked_masks = array_values($checked_masks);
1244				}
1245			}
1246			$bestMask = $frame;
1247			foreach ($checked_masks as $i) {
1248				$mask = array_fill(0, $width, str_repeat("\0", $width));
1249				$demerit = 0;
1250				$blacks = 0;
1251				$blacks  = $this->makeMaskNo($i, $width, $frame, $mask);
1252				$blacks += $this->writeFormatInformation($width, $mask, $i, $level);
1253				$blacks  = (int)(100 * $blacks / ($width * $width));
1254				$demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
1255				$demerit += $this->evaluateSymbol($width, $mask);
1256				if ($demerit < $minDemerit) {
1257					$minDemerit = $demerit;
1258					$bestMask = $mask;
1259					$bestMaskNum = $i;
1260				}
1261			}
1262			return $bestMask;
1263		}
1264
1265		// - - - - - - - - - - - - - - - - - - - - - - - - -
1266
1267		// QRsplit
1268
1269		/**
1270		 * Return true if the character at specified position is a number
1271		 * @param string $str string
1272		 * @param int $pos characted position
1273		 * @return boolean true of false
1274		 */
1275		 protected function isdigitat($str, $pos) {
1276			if ($pos >= strlen($str)) {
1277				return false;
1278			}
1279			return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
1280		}
1281
1282		/**
1283		 * Return true if the character at specified position is an alphanumeric character
1284		 * @param string $str string
1285		 * @param int $pos characted position
1286		 * @return boolean true of false
1287		 */
1288		 protected function isalnumat($str, $pos) {
1289			if ($pos >= strlen($str)) {
1290				return false;
1291			}
1292			return ($this->lookAnTable(ord($str[$pos])) >= 0);
1293		}
1294
1295		/**
1296		 * identifyMode
1297		 * @param int $pos
1298		 * @return int mode
1299		 */
1300		 protected function identifyMode($pos) {
1301			if ($pos >= strlen($this->dataStr)) {
1302				return QR_MODE_NL;
1303			}
1304			$c = $this->dataStr[$pos];
1305			if ($this->isdigitat($this->dataStr, $pos)) {
1306				return QR_MODE_NM;
1307			} elseif ($this->isalnumat($this->dataStr, $pos)) {
1308				return QR_MODE_AN;
1309			} elseif ($this->hint == QR_MODE_KJ) {
1310				if ($pos+1 < strlen($this->dataStr)) {
1311					$d = $this->dataStr[$pos+1];
1312					$word = (ord($c) << 8) | ord($d);
1313					if (($word >= 0x8140 && $word <= 0x9ffc) OR ($word >= 0xe040 && $word <= 0xebbf)) {
1314						return QR_MODE_KJ;
1315					}
1316				}
1317			}
1318			return QR_MODE_8B;
1319		}
1320
1321		/**
1322		 * eatNum
1323		 * @return int run
1324		 */
1325		 protected function eatNum() {
1326			$ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1327			$p = 0;
1328			while($this->isdigitat($this->dataStr, $p)) {
1329				$p++;
1330			}
1331			$run = $p;
1332			$mode = $this->identifyMode($p);
1333			if ($mode == QR_MODE_8B) {
1334				$dif = $this->estimateBitsModeNum($run) + 4 + $ln
1335				+ $this->estimateBitsMode8(1)         // + 4 + l8
1336				- $this->estimateBitsMode8($run + 1); // - 4 - l8
1337				if ($dif > 0) {
1338					return $this->eat8();
1339				}
1340			}
1341			if ($mode == QR_MODE_AN) {
1342				$dif = $this->estimateBitsModeNum($run) + 4 + $ln
1343				+ $this->estimateBitsModeAn(1)        // + 4 + la
1344				- $this->estimateBitsModeAn($run + 1);// - 4 - la
1345				if ($dif > 0) {
1346					return $this->eatAn();
1347				}
1348			}
1349			$this->items = $this->appendNewInputItem($this->items, QR_MODE_NM, $run, str_split($this->dataStr));
1350			return $run;
1351		}
1352
1353		/**
1354		 * eatAn
1355		 * @return int run
1356		 */
1357		 protected function eatAn() {
1358			$la = $this->lengthIndicator(QR_MODE_AN,  $this->version);
1359			$ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1360			$p = 0;
1361			while($this->isalnumat($this->dataStr, $p)) {
1362				if ($this->isdigitat($this->dataStr, $p)) {
1363					$q = $p;
1364					while($this->isdigitat($this->dataStr, $q)) {
1365						$q++;
1366					}
1367					$dif = $this->estimateBitsModeAn($p) // + 4 + la
1368					+ $this->estimateBitsModeNum($q - $p) + 4 + $ln
1369					- $this->estimateBitsModeAn($q); // - 4 - la
1370					if ($dif < 0) {
1371						break;
1372					} else {
1373						$p = $q;
1374					}
1375				} else {
1376					$p++;
1377				}
1378			}
1379			$run = $p;
1380			if (!$this->isalnumat($this->dataStr, $p)) {
1381				$dif = $this->estimateBitsModeAn($run) + 4 + $la
1382				+ $this->estimateBitsMode8(1) // + 4 + l8
1383				- $this->estimateBitsMode8($run + 1); // - 4 - l8
1384				if ($dif > 0) {
1385					return $this->eat8();
1386				}
1387			}
1388			$this->items = $this->appendNewInputItem($this->items, QR_MODE_AN, $run, str_split($this->dataStr));
1389			return $run;
1390		}
1391
1392		/**
1393		 * eatKanji
1394		 * @return int run
1395		 */
1396		 protected function eatKanji() {
1397			$p = 0;
1398			while($this->identifyMode($p) == QR_MODE_KJ) {
1399				$p += 2;
1400			}
1401			$this->items = $this->appendNewInputItem($this->items, QR_MODE_KJ, $p, str_split($this->dataStr));
1402			return $run;
1403		}
1404
1405		/**
1406		 * eat8
1407		 * @return int run
1408		 */
1409		 protected function eat8() {
1410			$la = $this->lengthIndicator(QR_MODE_AN, $this->version);
1411			$ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1412			$p = 1;
1413			$dataStrLen = strlen($this->dataStr);
1414			while($p < $dataStrLen) {
1415				$mode = $this->identifyMode($p);
1416				if ($mode == QR_MODE_KJ) {
1417					break;
1418				}
1419				if ($mode == QR_MODE_NM) {
1420					$q = $p;
1421					while($this->isdigitat($this->dataStr, $q)) {
1422						$q++;
1423					}
1424					$dif = $this->estimateBitsMode8($p) // + 4 + l8
1425					+ $this->estimateBitsModeNum($q - $p) + 4 + $ln
1426					- $this->estimateBitsMode8($q); // - 4 - l8
1427					if ($dif < 0) {
1428						break;
1429					} else {
1430						$p = $q;
1431					}
1432				} elseif ($mode == QR_MODE_AN) {
1433					$q = $p;
1434					while($this->isalnumat($this->dataStr, $q)) {
1435						$q++;
1436					}
1437					$dif = $this->estimateBitsMode8($p)  // + 4 + l8
1438					+ $this->estimateBitsModeAn($q - $p) + 4 + $la
1439					- $this->estimateBitsMode8($q); // - 4 - l8
1440					if ($dif < 0) {
1441						break;
1442					} else {
1443						$p = $q;
1444					}
1445				} else {
1446					$p++;
1447				}
1448			}
1449			$run = $p;
1450			$this->items = $this->appendNewInputItem($this->items, QR_MODE_8B, $run, str_split($this->dataStr));
1451			return $run;
1452		}
1453
1454		/**
1455		 * splitString
1456		 */
1457		 protected function splitString() {
1458			while (strlen($this->dataStr) > 0) {
1459				if ($this->dataStr == '') {
1460					return 0;
1461				}
1462				$mode = $this->identifyMode(0);
1463				switch ($mode) {
1464					case QR_MODE_NM: {
1465						$length = $this->eatNum();
1466						break;
1467					}
1468					case QR_MODE_AN: {
1469						$length = $this->eatAn();
1470						break;
1471					}
1472					case QR_MODE_KJ: {
1473						if ($hint == QR_MODE_KJ) {
1474							$length = $this->eatKanji();
1475						} else {
1476							$length = $this->eat8();
1477						}
1478						break;
1479					}
1480					default: {
1481						$length = $this->eat8();
1482						break;
1483					}
1484				}
1485				if ($length == 0) {
1486					return 0;
1487				}
1488				if ($length < 0) {
1489					return -1;
1490				}
1491				$this->dataStr = substr($this->dataStr, $length);
1492			}
1493		}
1494
1495		/**
1496		 * toUpper
1497		 */
1498		 protected function toUpper() {
1499			$stringLen = strlen($this->dataStr);
1500			$p = 0;
1501			while ($p < $stringLen) {
1502				$mode = $this->identifyMode(substr($this->dataStr, $p), $this->hint);
1503				if ($mode == QR_MODE_KJ) {
1504					$p += 2;
1505				} else {
1506					if ((ord($this->dataStr[$p]) >= ord('a')) AND (ord($this->dataStr[$p]) <= ord('z'))) {
1507						$this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
1508					}
1509					$p++;
1510				}
1511			}
1512			return $this->dataStr;
1513		}
1514
1515		// - - - - - - - - - - - - - - - - - - - - - - - - -
1516
1517		// QRinputItem
1518
1519		/**
1520		 * newInputItem
1521		 * @param int $mode
1522		 * @param int $size
1523		 * @param array $data
1524		 * @param array $bstream
1525		 * @return array input item
1526		 */
1527		 protected function newInputItem($mode, $size, $data, $bstream=null) {
1528			$setData = array_slice($data, 0, $size);
1529			if (count($setData) < $size) {
1530				$setData = array_merge($setData, array_fill(0, ($size - count($setData)), 0));
1531			}
1532			if (!$this->check($mode, $size, $setData)) {
1533				return NULL;
1534			}
1535			$inputitem = array();
1536			$inputitem['mode'] = $mode;
1537			$inputitem['size'] = $size;
1538			$inputitem['data'] = $setData;
1539			$inputitem['bstream'] = $bstream;
1540			return $inputitem;
1541		}
1542
1543		/**
1544		 * encodeModeNum
1545		 * @param array $inputitem
1546		 * @param int $version
1547		 * @return array input item
1548		 */
1549		 protected function encodeModeNum($inputitem, $version) {
1550			$words = (int)($inputitem['size'] / 3);
1551			$inputitem['bstream'] = array();
1552			$val = 0x1;
1553			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
1554			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_NM, $version), $inputitem['size']);
1555			for ($i=0; $i < $words; ++$i) {
1556				$val  = (ord($inputitem['data'][$i*3  ]) - ord('0')) * 100;
1557				$val += (ord($inputitem['data'][$i*3+1]) - ord('0')) * 10;
1558				$val += (ord($inputitem['data'][$i*3+2]) - ord('0'));
1559				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 10, $val);
1560			}
1561			if ($inputitem['size'] - $words * 3 == 1) {
1562				$val = ord($inputitem['data'][$words*3]) - ord('0');
1563				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
1564			} elseif (($inputitem['size'] - ($words * 3)) == 2) {
1565				$val  = (ord($inputitem['data'][$words*3  ]) - ord('0')) * 10;
1566				$val += (ord($inputitem['data'][$words*3+1]) - ord('0'));
1567				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 7, $val);
1568			}
1569			return $inputitem;
1570		}
1571
1572		/**
1573		 * encodeModeAn
1574		 * @param array $inputitem
1575		 * @param int $version
1576		 * @return array input item
1577		 */
1578		 protected function encodeModeAn($inputitem, $version) {
1579			$words = (int)($inputitem['size'] / 2);
1580			$inputitem['bstream'] = array();
1581			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x02);
1582			$inputitem['bstream'] = $this->appendNum(v, $this->lengthIndicator(QR_MODE_AN, $version), $inputitem['size']);
1583			for ($i=0; $i < $words; ++$i) {
1584				$val  = (int)$this->lookAnTable(ord($inputitem['data'][$i*2  ])) * 45;
1585				$val += (int)$this->lookAnTable(ord($inputitem['data'][$i*2+1]));
1586				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 11, $val);
1587			}
1588			if ($inputitem['size'] & 1) {
1589				$val = $this->lookAnTable(ord($inputitem['data'][($words * 2)]));
1590				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 6, $val);
1591			}
1592			return $inputitem;
1593		}
1594
1595		/**
1596		 * encodeMode8
1597		 * @param array $inputitem
1598		 * @param int $version
1599		 * @return array input item
1600		 */
1601		 protected function encodeMode8($inputitem, $version) {
1602			$inputitem['bstream'] = array();
1603			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x4);
1604			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_8B, $version), $inputitem['size']);
1605			for ($i=0; $i < $inputitem['size']; ++$i) {
1606				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][$i]));
1607			}
1608			return $inputitem;
1609		}
1610
1611		/**
1612		 * encodeModeKanji
1613		 * @param array $inputitem
1614		 * @param int $version
1615		 * @return array input item
1616		 */
1617		 protected function encodeModeKanji($inputitem, $version) {
1618			$inputitem['bstream'] = array();
1619			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x8);
1620			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_KJ, $version), (int)($inputitem['size'] / 2));
1621			for ($i=0; $i<$inputitem['size']; $i+=2) {
1622				$val = (ord($inputitem['data'][$i]) << 8) | ord($inputitem['data'][$i+1]);
1623				if ($val <= 0x9ffc) {
1624					$val -= 0x8140;
1625				} else {
1626					$val -= 0xc140;
1627				}
1628				$h = ($val >> 8) * 0xc0;
1629				$val = ($val & 0xff) + $h;
1630				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 13, $val);
1631			}
1632			return $inputitem;
1633		}
1634
1635		/**
1636		 * encodeModeStructure
1637		 * @param array $inputitem
1638		 * @return array input item
1639		 */
1640		 protected function encodeModeStructure($inputitem) {
1641			$inputitem['bstream'] = array();
1642			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x03);
1643			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][1]) - 1);
1644			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][0]) - 1);
1645			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][2]));
1646			return $inputitem;
1647		}
1648
1649		/**
1650		 * encodeBitStream
1651		 * @param array $inputitem
1652		 * @param int $version
1653		 * @return array input item
1654		 */
1655		 protected function encodeBitStream($inputitem, $version) {
1656			$inputitem['bstream'] = array();
1657			$words = $this->maximumWords($inputitem['mode'], $version);
1658			if ($inputitem['size'] > $words) {
1659				$st1 = $this->newInputItem($inputitem['mode'], $words, $inputitem['data']);
1660				$st2 = $this->newInputItem($inputitem['mode'], $inputitem['size'] - $words, array_slice($inputitem['data'], $words));
1661				$st1 = $this->encodeBitStream($st1, $version);
1662				$st2 = $this->encodeBitStream($st2, $version);
1663				$inputitem['bstream'] = array();
1664				$inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st1['bstream']);
1665				$inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st2['bstream']);
1666			} else {
1667				switch($inputitem['mode']) {
1668					case QR_MODE_NM: {
1669						$inputitem = $this->encodeModeNum($inputitem, $version);
1670						break;
1671					}
1672					case QR_MODE_AN: {
1673						$inputitem = $this->encodeModeAn($inputitem, $version);
1674						break;
1675					}
1676					case QR_MODE_8B: {
1677						$inputitem = $this->encodeMode8($inputitem, $version);
1678						break;
1679					}
1680					case QR_MODE_KJ: {
1681						$inputitem = $this->encodeModeKanji($inputitem, $version);
1682						break;
1683					}
1684					case QR_MODE_ST: {
1685						$inputitem = $this->encodeModeStructure($inputitem);
1686						break;
1687					}
1688					default: {
1689						break;
1690					}
1691				}
1692			}
1693			return $inputitem;
1694		}
1695
1696		// - - - - - - - - - - - - - - - - - - - - - - - - -
1697
1698		// QRinput
1699
1700		/**
1701		 * Append data to an input object.
1702		 * The data is copied and appended to the input object.
1703		 * @param array items input items
1704		 * @param int $mode encoding mode.
1705		 * @param int $size size of data (byte).
1706		 * @param array $data array of input data.
1707		 * @return items
1708		 *
1709		 */
1710		protected function appendNewInputItem($items, $mode, $size, $data) {
1711			$items[] = $this->newInputItem($mode, $size, $data);
1712			return $items;
1713		}
1714
1715		/**
1716		 * insertStructuredAppendHeader
1717		 * @param array $items
1718		 * @param int $size
1719		 * @param int $index
1720		 * @param int $parity
1721		 * @return array items
1722		 */
1723		 protected function insertStructuredAppendHeader($items, $size, $index, $parity) {
1724			if ($size > MAX_STRUCTURED_SYMBOLS) {
1725				return -1;
1726			}
1727			if (($index <= 0) OR ($index > MAX_STRUCTURED_SYMBOLS)) {
1728				return -1;
1729			}
1730			$buf = array($size, $index, $parity);
1731			$entry = $this->newInputItem(QR_MODE_ST, 3, buf);
1732			array_unshift($items, $entry);
1733			return $items;
1734		}
1735
1736		/**
1737		 * calcParity
1738		 * @param array $items
1739		 * @return int parity
1740		 */
1741		 protected function calcParity($items) {
1742			$parity = 0;
1743			foreach ($items as $item) {
1744				if ($item['mode'] != QR_MODE_ST) {
1745					for ($i=$item['size']-1; $i>=0; --$i) {
1746						$parity ^= $item['data'][$i];
1747					}
1748				}
1749			}
1750			return $parity;
1751		}
1752
1753		/**
1754		 * checkModeNum
1755		 * @param int $size
1756		 * @param array $data
1757		 * @return boolean true or false
1758		 */
1759		 protected function checkModeNum($size, $data) {
1760			for ($i=0; $i<$size; ++$i) {
1761				if ((ord($data[$i]) < ord('0')) OR (ord($data[$i]) > ord('9'))){
1762					return false;
1763				}
1764			}
1765			return true;
1766		}
1767
1768		/**
1769		 * estimateBitsModeNum
1770		 * @param int $size
1771		 * @return int number of bits
1772		 */
1773		 protected function estimateBitsModeNum($size) {
1774			$w = (int)$size / 3;
1775			$bits = $w * 10;
1776			switch($size - $w * 3) {
1777				case 1: {
1778					$bits += 4;
1779					break;
1780				}
1781				case 2: {
1782					$bits += 7;
1783					break;
1784				}
1785				default: {
1786					break;
1787				}
1788			}
1789			return $bits;
1790		}
1791
1792		/**
1793		 * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
1794		 * @param int $c character value
1795		 * @return value
1796		 */
1797		protected function lookAnTable($c) {
1798			return (($c > 127)?-1:$this->anTable[$c]);
1799		}
1800
1801		/**
1802		 * checkModeAn
1803		 * @param int $size
1804		 * @param array $data
1805		 * @return boolean true or false
1806		 */
1807		 protected function checkModeAn($size, $data) {
1808			for ($i=0; $i<$size; ++$i) {
1809				if ($this->lookAnTable(ord($data[$i])) == -1) {
1810					return false;
1811				}
1812			}
1813			return true;
1814		}
1815
1816		/**
1817		 * estimateBitsModeAn
1818		 * @param int $size
1819		 * @return int number of bits
1820		 */
1821		 protected function estimateBitsModeAn($size) {
1822			$w = (int)($size / 2);
1823			$bits = $w * 11;
1824			if ($size & 1) {
1825				$bits += 6;
1826			}
1827			return $bits;
1828		}
1829
1830		/**
1831		 * estimateBitsMode8
1832		 * @param int $size
1833		 * @return int number of bits
1834		 */
1835		 protected function estimateBitsMode8($size) {
1836			return $size * 8;
1837		}
1838
1839		/**
1840		 * estimateBitsModeKanji
1841		 * @param int $size
1842		 * @return int number of bits
1843		 */
1844		 protected function estimateBitsModeKanji($size) {
1845			return (int)(($size / 2) * 13);
1846		}
1847
1848		/**
1849		 * checkModeKanji
1850		 * @param int $size
1851		 * @param array $data
1852		 * @return boolean true or false
1853		 */
1854		 protected function checkModeKanji($size, $data) {
1855			if ($size & 1) {
1856				return false;
1857			}
1858			for ($i=0; $i<$size; $i+=2) {
1859				$val = (ord($data[$i]) << 8) | ord($data[$i+1]);
1860				if (($val < 0x8140) OR (($val > 0x9ffc) AND ($val < 0xe040)) OR ($val > 0xebbf)) {
1861					return false;
1862				}
1863			}
1864			return true;
1865		}
1866
1867		/**
1868		 * Validate the input data.
1869		 * @param int $mode encoding mode.
1870		 * @param int $size size of data (byte).
1871		 * @param array data data to validate
1872		 * @return boolean true in case of valid data, false otherwise
1873		 */
1874		protected function check($mode, $size, $data) {
1875			if ($size <= 0) {
1876				return false;
1877			}
1878			switch($mode) {
1879				case QR_MODE_NM: {
1880					return $this->checkModeNum($size, $data);
1881				}
1882				case QR_MODE_AN: {
1883					return $this->checkModeAn($size, $data);
1884				}
1885				case QR_MODE_KJ: {
1886					return $this->checkModeKanji($size, $data);
1887				}
1888				case QR_MODE_8B: {
1889					return true;
1890				}
1891				case QR_MODE_ST: {
1892					return true;
1893				}
1894				default: {
1895					break;
1896				}
1897			}
1898			return false;
1899		}
1900
1901		/**
1902		 * estimateBitStreamSize
1903		 * @param array $items
1904		 * @param int $version
1905		 * @return int bits
1906		 */
1907		 protected function estimateBitStreamSize($items, $version) {
1908			$bits = 0;
1909			if ($version == 0) {
1910				$version = 1;
1911			}
1912			foreach ($items as $item) {
1913				switch($item['mode']) {
1914					case QR_MODE_NM: {
1915						$bits = $this->estimateBitsModeNum($item['size']);
1916						break;
1917					}
1918					case QR_MODE_AN: {
1919						$bits = $this->estimateBitsModeAn($item['size']);
1920						break;
1921					}
1922					case QR_MODE_8B: {
1923						$bits = $this->estimateBitsMode8($item['size']);
1924						break;
1925					}
1926					case QR_MODE_KJ: {
1927						$bits = $this->estimateBitsModeKanji($item['size']);
1928						break;
1929					}
1930					case QR_MODE_ST: {
1931						return STRUCTURE_HEADER_BITS;
1932					}
1933					default: {
1934						return 0;
1935					}
1936				}
1937				$l = $this->lengthIndicator($item['mode'], $version);
1938				$m = 1 << $l;
1939				$num = (int)(($item['size'] + $m - 1) / $m);
1940				$bits += $num * (4 + $l);
1941			}
1942			return $bits;
1943		}
1944
1945		/**
1946		 * estimateVersion
1947		 * @param array $items
1948		 * @return int version
1949		 */
1950		 protected function estimateVersion($items) {
1951			$version = 0;
1952			$prev = 0;
1953			do {
1954				$prev = $version;
1955				$bits = $this->estimateBitStreamSize($items, $prev);
1956				$version = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
1957				if ($version < 0) {
1958					return -1;
1959				}
1960			} while ($version > $prev);
1961			return $version;
1962		}
1963
1964		/**
1965		 * lengthOfCode
1966		 * @param int $mode
1967		 * @param int $version
1968		 * @param int $bits
1969		 * @return int size
1970		 */
1971		 protected function lengthOfCode($mode, $version, $bits) {
1972			$payload = $bits - 4 - $this->lengthIndicator($mode, $version);
1973			switch($mode) {
1974				case QR_MODE_NM: {
1975					$chunks = (int)($payload / 10);
1976					$remain = $payload - $chunks * 10;
1977					$size = $chunks * 3;
1978					if ($remain >= 7) {
1979						$size += 2;
1980					} elseif ($remain >= 4) {
1981						$size += 1;
1982					}
1983					break;
1984				}
1985				case QR_MODE_AN: {
1986					$chunks = (int)($payload / 11);
1987					$remain = $payload - $chunks * 11;
1988					$size = $chunks * 2;
1989					if ($remain >= 6) {
1990						++$size;
1991					}
1992					break;
1993				}
1994				case QR_MODE_8B: {
1995					$size = (int)($payload / 8);
1996					break;
1997				}
1998				case QR_MODE_KJ: {
1999					$size = (int)(($payload / 13) * 2);
2000					break;
2001				}
2002				case QR_MODE_ST: {
2003					$size = (int)($payload / 8);
2004					break;
2005				}
2006				default: {
2007					$size = 0;
2008					break;
2009				}
2010			}
2011			$maxsize = $this->maximumWords($mode, $version);
2012			if ($size < 0) {
2013				$size = 0;
2014			}
2015			if ($size > $maxsize) {
2016				$size = $maxsize;
2017			}
2018			return $size;
2019		}
2020
2021		/**
2022		 * createBitStream
2023		 * @param array $items
2024		 * @return array of items and total bits
2025		 */
2026		 protected function createBitStream($items) {
2027			$total = 0;
2028			foreach ($items as $key => $item) {
2029				$items[$key] = $this->encodeBitStream($item, $this->version);
2030				$bits = count($items[$key]['bstream']);
2031				$total += $bits;
2032			}
2033			return array($items, $total);
2034		}
2035
2036		/**
2037		 * convertData
2038		 * @param array $items
2039		 * @return array items
2040		 */
2041		 protected function convertData($items) {
2042			$ver = $this->estimateVersion($items);
2043			if ($ver > $this->version) {
2044				$this->version = $ver;
2045			}
2046			for (;;) {
2047				$cbs = $this->createBitStream($items);
2048				$items = $cbs[0];
2049				$bits = $cbs[1];
2050				if ($bits < 0) {
2051					return -1;
2052				}
2053				$ver = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
2054				if ($ver < 0) {
2055					return -1;
2056				} elseif ($ver > $this->version) {
2057					$this->version = $ver;
2058				} else {
2059					break;
2060				}
2061			}
2062			return $items;
2063		}
2064
2065		/**
2066		 * Append Padding Bit to bitstream
2067		 * @param array $bstream
2068		 * @return array bitstream
2069		 */
2070		 protected function appendPaddingBit($bstream) {
2071			$bits = count($bstream);
2072			$maxwords = $this->getDataLength($this->version, $this->level);
2073			$maxbits = $maxwords * 8;
2074			if ($maxbits == $bits) {
2075				return 0;
2076			}
2077			if ($maxbits - $bits < 5) {
2078				return $this->appendNum($bstream, $maxbits - $bits, 0);
2079			}
2080			$bits += 4;
2081			$words = (int)(($bits + 7) / 8);
2082			$padding = array();
2083			$padding = $this->appendNum($padding, $words * 8 - $bits + 4, 0);
2084			$padlen = $maxwords - $words;
2085			if ($padlen > 0) {
2086				$padbuf = array();
2087				for ($i=0; $i<$padlen; ++$i) {
2088					$padbuf[$i] = ($i&1)?0x11:0xec;
2089				}
2090				$padding = $this->appendBytes($padding, $padlen, $padbuf);
2091			}
2092			return $this->appendBitstream($bstream, $padding);
2093		}
2094
2095		/**
2096		 * mergeBitStream
2097		 * @param array $bstream
2098		 * @return array bitstream
2099		 */
2100		 protected function mergeBitStream($items) {
2101			$items = $this->convertData($items);
2102			$bstream = array();
2103			foreach ($items as $item) {
2104				$bstream = $this->appendBitstream($bstream, $item['bstream']);
2105			}
2106			return $bstream;
2107		}
2108
2109		/**
2110		 * Returns a stream of bits.
2111		 * @param int $items
2112		 * @return array padded merged byte stream
2113		 */
2114		protected function getBitStream($items) {
2115			$bstream = $this->mergeBitStream($items);
2116			return $this->appendPaddingBit($bstream);
2117		}
2118
2119		/**
2120		 * Pack all bit streams padding bits into a byte array.
2121		 * @param int $items
2122		 * @return array padded merged byte stream
2123		 */
2124		protected function getByteStream($items) {
2125			$bstream = $this->getBitStream($items);
2126			return $this->bitstreamToByte($bstream);
2127		}
2128
2129		// - - - - - - - - - - - - - - - - - - - - - - - - -
2130
2131		// QRbitstream
2132
2133		/**
2134		 * Return an array with zeros
2135		 * @param int $setLength array size
2136		 * @return array
2137		 */
2138		 protected function allocate($setLength) {
2139			return array_fill(0, $setLength, 0);
2140		}
2141
2142		/**
2143		 * Return new bitstream from number
2144		 * @param int $bits number of bits
2145		 * @param int $num number
2146		 * @return array bitstream
2147		 */
2148		 protected function newFromNum($bits, $num) {
2149			$bstream = $this->allocate($bits);
2150			$mask = 1 << ($bits - 1);
2151			for ($i=0; $i<$bits; ++$i) {
2152				if ($num & $mask) {
2153					$bstream[$i] = 1;
2154				} else {
2155					$bstream[$i] = 0;
2156				}
2157				$mask = $mask >> 1;
2158			}
2159			return $bstream;
2160		}
2161
2162		/**
2163		 * Return new bitstream from bytes
2164		 * @param int $size size
2165		 * @param array $data bytes
2166		 * @return array bitstream
2167		 */
2168		 protected function newFromBytes($size, $data) {
2169			$bstream = $this->allocate($size * 8);
2170			$p=0;
2171			for ($i=0; $i<$size; ++$i) {
2172				$mask = 0x80;
2173				for ($j=0; $j<8; ++$j) {
2174					if ($data[$i] & $mask) {
2175						$bstream[$p] = 1;
2176					} else {
2177						$bstream[$p] = 0;
2178					}
2179					$p++;
2180					$mask = $mask >> 1;
2181				}
2182			}
2183			return $bstream;
2184		}
2185
2186		/**
2187		 * Append one bitstream to another
2188		 * @param array $bitstream original bitstream
2189		 * @param array $append bitstream to append
2190		 * @return array bitstream
2191		 */
2192		 protected function appendBitstream($bitstream, $append) {
2193			if ((!is_array($append)) OR (count($append) == 0)) {
2194				return $bitstream;
2195			}
2196			if (count($bitstream) == 0) {
2197				return $append;
2198			}
2199			return array_values(array_merge($bitstream, $append));
2200		}
2201
2202		/**
2203		 * Append one bitstream created from number to another
2204		 * @param array $bitstream original bitstream
2205		 * @param int $bits number of bits
2206		 * @param int $num number
2207		 * @return array bitstream
2208		 */
2209		 protected function appendNum($bitstream, $bits, $num) {
2210			if ($bits == 0) {
2211				return 0;
2212			}
2213			$b = $this->newFromNum($bits, $num);
2214			return $this->appendBitstream($bitstream, $b);
2215		}
2216
2217		/**
2218		 * Append one bitstream created from bytes to another
2219		 * @param array $bitstream original bitstream
2220		 * @param int $size size
2221		 * @param array $data bytes
2222		 * @return array bitstream
2223		 */
2224		 protected function appendBytes($bitstream, $size, $data) {
2225			if ($size == 0) {
2226				return 0;
2227			}
2228			$b = $this->newFromBytes($size, $data);
2229			return $this->appendBitstream($bitstream, $b);
2230		}
2231
2232		/**
2233		 * Convert bitstream to bytes
2234		 * @param array $bitstream original bitstream
2235		 * @return array of bytes
2236		 */
2237		 protected function bitstreamToByte($bstream) {
2238			$size = count($bstream);
2239			if ($size == 0) {
2240				return array();
2241			}
2242			$data = array_fill(0, (int)(($size + 7) / 8), 0);
2243			$bytes = (int)($size / 8);
2244			$p = 0;
2245			for ($i=0; $i<$bytes; $i++) {
2246				$v = 0;
2247				for ($j=0; $j<8; $j++) {
2248					$v = $v << 1;
2249					$v |= $bstream[$p];
2250					$p++;
2251				}
2252				$data[$i] = $v;
2253			}
2254			if ($size & 7) {
2255				$v = 0;
2256				for ($j=0; $j<($size & 7); $j++) {
2257					$v = $v << 1;
2258					$v |= $bstream[$p];
2259					$p++;
2260				}
2261				$data[$bytes] = $v;
2262			}
2263			return $data;
2264		}
2265
2266		// - - - - - - - - - - - - - - - - - - - - - - - - -
2267
2268		// QRspec
2269
2270		/**
2271		 * Replace a value on the array at the specified position
2272		 * @param array $srctab
2273		 * @param int $x X position
2274		 * @param int $y Y position
2275		 * @param string $repl value to replace
2276		 * @param int $replLen length of the repl string
2277		 * @return array srctab
2278		 */
2279		 protected function qrstrset($srctab, $x, $y, $repl, $replLen=false) {
2280			$srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
2281			return $srctab;
2282		}
2283
2284		/**
2285		 * Return maximum data code length (bytes) for the version.
2286		 * @param int $version version
2287		 * @param int $level error correction level
2288		 * @return int maximum size (bytes)
2289		 */
2290		protected function getDataLength($version, $level) {
2291			return $this->capacity[$version][QRCAP_WORDS] - $this->capacity[$version][QRCAP_EC][$level];
2292		}
2293
2294		/**
2295		 * Return maximum error correction code length (bytes) for the version.
2296		 * @param int $version version
2297		 * @param int $level error correction level
2298		 * @return int ECC size (bytes)
2299		 */
2300		protected function getECCLength($version, $level){
2301			return $this->capacity[$version][QRCAP_EC][$level];
2302		}
2303
2304		/**
2305		 * Return the width of the symbol for the version.
2306		 * @param int $version version
2307		 * @return int width
2308		 */
2309		protected function getWidth($version) {
2310			return $this->capacity[$version][QRCAP_WIDTH];
2311		}
2312
2313		/**
2314		 * Return the numer of remainder bits.
2315		 * @param int $version version
2316		 * @return int number of remainder bits
2317		 */
2318		protected function getRemainder($version) {
2319			return $this->capacity[$version][QRCAP_REMINDER];
2320		}
2321
2322		/**
2323		 * Return a version number that satisfies the input code length.
2324		 * @param int $size input code length (byte)
2325		 * @param int $level error correction level
2326		 * @return int version number
2327		 */
2328		protected function getMinimumVersion($size, $level) {
2329			for ($i=1; $i <= QRSPEC_VERSION_MAX; ++$i) {
2330				$words  = $this->capacity[$i][QRCAP_WORDS] - $this->capacity[$i][QRCAP_EC][$level];
2331				if ($words >= $size) {
2332					return $i;
2333				}
2334			}
2335			return -1;
2336		}
2337
2338		/**
2339		 * Return the size of length indicator for the mode and version.
2340		 * @param int $mode encoding mode
2341		 * @param int $version version
2342		 * @return int the size of the appropriate length indicator (bits).
2343		 */
2344		protected function lengthIndicator($mode, $version) {
2345			if ($mode == QR_MODE_ST) {
2346				return 0;
2347			}
2348			if ($version <= 9) {
2349				$l = 0;
2350			} elseif ($version <= 26) {
2351				$l = 1;
2352			} else {
2353				$l = 2;
2354			}
2355			return $this->lengthTableBits[$mode][$l];
2356		}
2357
2358		/**
2359		 * Return the maximum length for the mode and version.
2360		 * @param int $mode encoding mode
2361		 * @param int $version version
2362		 * @return int the maximum length (bytes)
2363		 */
2364		protected function maximumWords($mode, $version) {
2365			if ($mode == QR_MODE_ST) {
2366				return 3;
2367			}
2368			if ($version <= 9) {
2369				$l = 0;
2370			} else if ($version <= 26) {
2371				$l = 1;
2372			} else {
2373				$l = 2;
2374			}
2375			$bits = $this->lengthTableBits[$mode][$l];
2376			$words = (1 << $bits) - 1;
2377			if ($mode == QR_MODE_KJ) {
2378				$words *= 2; // the number of bytes is required
2379			}
2380			return $words;
2381		}
2382
2383		/**
2384		 * Return an array of ECC specification.
2385		 * @param int $version version
2386		 * @param int $level error correction level
2387		 * @param array $spec an array of ECC specification contains as following: {# of type1 blocks, # of data code, # of ecc code, # of type2 blocks, # of data code}
2388		 * @return array spec
2389		 */
2390		protected function getEccSpec($version, $level, $spec) {
2391			if (count($spec) < 5) {
2392				$spec = array(0, 0, 0, 0, 0);
2393			}
2394			$b1 = $this->eccTable[$version][$level][0];
2395			$b2 = $this->eccTable[$version][$level][1];
2396			$data = $this->getDataLength($version, $level);
2397			$ecc = $this->getECCLength($version, $level);
2398			if ($b2 == 0) {
2399				$spec[0] = $b1;
2400				$spec[1] = (int)($data / $b1);
2401				$spec[2] = (int)($ecc / $b1);
2402				$spec[3] = 0;
2403				$spec[4] = 0;
2404			} else {
2405				$spec[0] = $b1;
2406				$spec[1] = (int)($data / ($b1 + $b2));
2407				$spec[2] = (int)($ecc  / ($b1 + $b2));
2408				$spec[3] = $b2;
2409				$spec[4] = $spec[1] + 1;
2410			}
2411			return $spec;
2412		}
2413
2414		/**
2415		 * Put an alignment marker.
2416		 * @param array $frame frame
2417		 * @param int $width width
2418		 * @param int $ox X center coordinate of the pattern
2419		 * @param int $oy Y center coordinate of the pattern
2420		 * @return array frame
2421		 */
2422		protected function putAlignmentMarker($frame, $ox, $oy) {
2423			$finder = array(
2424				"\xa1\xa1\xa1\xa1\xa1",
2425				"\xa1\xa0\xa0\xa0\xa1",
2426				"\xa1\xa0\xa1\xa0\xa1",
2427				"\xa1\xa0\xa0\xa0\xa1",
2428				"\xa1\xa1\xa1\xa1\xa1"
2429				);
2430			$yStart = $oy - 2;
2431			$xStart = $ox - 2;
2432			for ($y=0; $y < 5; $y++) {
2433				$frame = $this->qrstrset($frame, $xStart, $yStart+$y, $finder[$y]);
2434			}
2435			return $frame;
2436		}
2437
2438		/**
2439		 * Put an alignment pattern.
2440		 * @param int $version version
2441		 * @param array $fram frame
2442		 * @param int $width width
2443		 * @return array frame
2444		 */
2445		 protected function putAlignmentPattern($version, $frame, $width) {
2446			if ($version < 2) {
2447				return $frame;
2448			}
2449			$d = $this->alignmentPattern[$version][1] - $this->alignmentPattern[$version][0];
2450			if ($d < 0) {
2451				$w = 2;
2452			} else {
2453				$w = (int)(($width - $this->alignmentPattern[$version][0]) / $d + 2);
2454			}
2455			if ($w * $w - 3 == 1) {
2456				$x = $this->alignmentPattern[$version][0];
2457				$y = $this->alignmentPattern[$version][0];
2458				$frame = $this->putAlignmentMarker($frame, $x, $y);
2459				return $frame;
2460			}
2461			$cx = $this->alignmentPattern[$version][0];
2462			$wo = $w - 1;
2463			for ($x=1; $x < $wo; ++$x) {
2464				$frame = $this->putAlignmentMarker($frame, 6, $cx);
2465				$frame = $this->putAlignmentMarker($frame, $cx,  6);
2466				$cx += $d;
2467			}
2468			$cy = $this->alignmentPattern[$version][0];
2469			for ($y=0; $y < $wo; ++$y) {
2470				$cx = $this->alignmentPattern[$version][0];
2471				for ($x=0; $x < $wo; ++$x) {
2472					$frame = $this->putAlignmentMarker($frame, $cx, $cy);
2473					$cx += $d;
2474				}
2475				$cy += $d;
2476			}
2477			return $frame;
2478		}
2479
2480		/**
2481		 * Return BCH encoded version information pattern that is used for the symbol of version 7 or greater. Use lower 18 bits.
2482		 * @param int $version version
2483		 * @return BCH encoded version information pattern
2484		 */
2485		protected function getVersionPattern($version) {
2486			if (($version < 7) OR ($version > QRSPEC_VERSION_MAX)) {
2487				return 0;
2488			}
2489			return $this->versionPattern[($version - 7)];
2490		}
2491
2492		/**
2493		 * Return BCH encoded format information pattern.
2494		 * @param array $mask
2495		 * @param int $level error correction level
2496		 * @return BCH encoded format information pattern
2497		 */
2498		protected function getFormatInfo($mask, $level) {
2499			if (($mask < 0) OR ($mask > 7)) {
2500				return 0;
2501			}
2502			if (($level < 0) OR ($level > 3)) {
2503				return 0;
2504			}
2505			return $this->formatInfo[$level][$mask];
2506		}
2507
2508		/**
2509		 * Put a finder pattern.
2510		 * @param array $frame frame
2511		 * @param int $width width
2512		 * @param int $ox X center coordinate of the pattern
2513		 * @param int $oy Y center coordinate of the pattern
2514		 * @return array frame
2515		 */
2516		protected function putFinderPattern($frame, $ox, $oy) {
2517			$finder = array(
2518			"\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
2519			"\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
2520			"\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2521			"\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2522			"\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2523			"\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
2524			"\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
2525			);
2526			for ($y=0; $y < 7; $y++) {
2527				$frame = $this->qrstrset($frame, $ox, ($oy + $y), $finder[$y]);
2528			}
2529			return $frame;
2530		}
2531
2532		/**
2533		 * Return a copy of initialized frame.
2534		 * @param int $version version
2535		 * @return Array of unsigned char.
2536		 */
2537		protected function createFrame($version) {
2538			$width = $this->capacity[$version][QRCAP_WIDTH];
2539			$frameLine = str_repeat ("\0", $width);
2540			$frame = array_fill(0, $width, $frameLine);
2541			// Finder pattern
2542			$frame = $this->putFinderPattern($frame, 0, 0);
2543			$frame = $this->putFinderPattern($frame, $width - 7, 0);
2544			$frame = $this->putFinderPattern($frame, 0, $width - 7);
2545			// Separator
2546			$yOffset = $width - 7;
2547			for ($y=0; $y < 7; ++$y) {
2548				$frame[$y][7] = "\xc0";
2549				$frame[$y][$width - 8] = "\xc0";
2550				$frame[$yOffset][7] = "\xc0";
2551				++$yOffset;
2552			}
2553			$setPattern = str_repeat("\xc0", 8);
2554			$frame = $this->qrstrset($frame, 0, 7, $setPattern);
2555			$frame = $this->qrstrset($frame, $width-8, 7, $setPattern);
2556			$frame = $this->qrstrset($frame, 0, $width - 8, $setPattern);
2557			// Format info
2558			$setPattern = str_repeat("\x84", 9);
2559			$frame = $this->qrstrset($frame, 0, 8, $setPattern);
2560			$frame = $this->qrstrset($frame, $width - 8, 8, $setPattern, 8);
2561			$yOffset = $width - 8;
2562			for ($y=0; $y < 8; ++$y,++$yOffset) {
2563				$frame[$y][8] = "\x84";
2564				$frame[$yOffset][8] = "\x84";
2565			}
2566			// Timing pattern
2567			$wo = $width - 15;
2568			for ($i=1; $i < $wo; ++$i) {
2569				$frame[6][7+$i] = chr(0x90 | ($i & 1));
2570				$frame[7+$i][6] = chr(0x90 | ($i & 1));
2571			}
2572			// Alignment pattern
2573			$frame = $this->putAlignmentPattern($version, $frame, $width);
2574			// Version information
2575			if ($version >= 7) {
2576				$vinf = $this->getVersionPattern($version);
2577				$v = $vinf;
2578				for ($x=0; $x<6; ++$x) {
2579					for ($y=0; $y<3; ++$y) {
2580						$frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1));
2581						$v = $v >> 1;
2582					}
2583				}
2584				$v = $vinf;
2585				for ($y=0; $y<6; ++$y) {
2586					for ($x=0; $x<3; ++$x) {
2587						$frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1));
2588						$v = $v >> 1;
2589					}
2590				}
2591			}
2592			// and a little bit...
2593			$frame[$width - 8][8] = "\x81";
2594			return $frame;
2595		}
2596
2597		/**
2598		 * Set new frame for the specified version.
2599		 * @param int $version version
2600		 * @return Array of unsigned char.
2601		 */
2602		protected function newFrame($version) {
2603			if (($version < 1) OR ($version > QRSPEC_VERSION_MAX)) {
2604				return NULL;
2605			}
2606			if (!isset($this->frames[$version])) {
2607				$this->frames[$version] = $this->createFrame($version);
2608			}
2609			if (is_null($this->frames[$version])) {
2610				return NULL;
2611			}
2612			return $this->frames[$version];
2613		}
2614
2615		/**
2616		 * Return block number 0
2617		 * @param array $spec
2618		 * @return int value
2619		 */
2620		 protected function rsBlockNum($spec) {
2621			return ($spec[0] + $spec[3]);
2622		}
2623
2624		/**
2625		* Return block number 1
2626		 * @param array $spec
2627		 * @return int value
2628		 */
2629		 protected function rsBlockNum1($spec) {
2630			return $spec[0];
2631		}
2632
2633		/**
2634		 * Return data codes 1
2635		 * @param array $spec
2636		 * @return int value
2637		 */
2638		 protected function rsDataCodes1($spec) {
2639			return $spec[1];
2640		}
2641
2642		/**
2643		 * Return ecc codes 1
2644		 * @param array $spec
2645		 * @return int value
2646		 */
2647		 protected function rsEccCodes1($spec) {
2648			return $spec[2];
2649		}
2650
2651		/**
2652		 * Return block number 2
2653		 * @param array $spec
2654		 * @return int value
2655		 */
2656		 protected function rsBlockNum2($spec) {
2657			return $spec[3];
2658		}
2659
2660		/**
2661		 * Return data codes 2
2662		 * @param array $spec
2663		 * @return int value
2664		 */
2665		 protected function rsDataCodes2($spec) {
2666			return $spec[4];
2667		}
2668
2669		/**
2670		 * Return ecc codes 2
2671		 * @param array $spec
2672		 * @return int value
2673		 */
2674		 protected function rsEccCodes2($spec) {
2675			return $spec[2];
2676		}
2677
2678		/**
2679		 * Return data length
2680		 * @param array $spec
2681		 * @return int value
2682		 */
2683		 protected function rsDataLength($spec) {
2684			return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]);
2685		}
2686
2687		/**
2688		 * Return ecc length
2689		 * @param array $spec
2690		 * @return int value
2691		 */
2692		 protected function rsEccLength($spec) {
2693			return ($spec[0] + $spec[3]) * $spec[2];
2694		}
2695
2696		// - - - - - - - - - - - - - - - - - - - - - - - - -
2697
2698		// QRrs
2699
2700		/**
2701		 * Initialize a Reed-Solomon codec and add it to existing rsitems
2702		 * @param int $symsize symbol size, bits
2703		 * @param int $gfpoly  Field generator polynomial coefficients
2704		 * @param int $fcr  first root of RS code generator polynomial, index form
2705		 * @param int $prim  primitive element to generate polynomial roots
2706		 * @param int $nroots RS code generator polynomial degree (number of roots)
2707		 * @param int $pad  padding bytes at front of shortened block
2708		 * @return array Array of RS values:<ul><li>mm = Bits per symbol;</li><li>nn = Symbols per block;</li><li>alpha_to = log lookup table array;</li><li>index_of = Antilog lookup table array;</li><li>genpoly = Generator polynomial array;</li><li>nroots = Number of generator;</li><li>roots = number of parity symbols;</li><li>fcr = First consecutive root, index form;</li><li>prim = Primitive element, index form;</li><li>iprim = prim-th root of 1, index form;</li><li>pad = Padding bytes in shortened block;</li><li>gfpoly</ul>.
2709		 */
2710		 protected function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
2711			foreach ($this->rsitems as $rs) {
2712				if (($rs['pad'] != $pad) OR ($rs['nroots'] != $nroots) OR ($rs['mm'] != $symsize)
2713					OR ($rs['gfpoly'] != $gfpoly) OR ($rs['fcr'] != $fcr) OR ($rs['prim'] != $prim)) {
2714					continue;
2715				}
2716				return $rs;
2717			}
2718			$rs = $this->init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
2719			array_unshift($this->rsitems, $rs);
2720			return $rs;
2721		}
2722
2723		// - - - - - - - - - - - - - - - - - - - - - - - - -
2724
2725		// QRrsItem
2726
2727		/**
2728		 * modnn
2729		 * @param array RS values
2730		 * @param int $x X position
2731		 * @return int X osition
2732		 */
2733		 protected function modnn($rs, $x) {
2734			while ($x >= $rs['nn']) {
2735				$x -= $rs['nn'];
2736				$x = ($x >> $rs['mm']) + ($x & $rs['nn']);
2737			}
2738			return $x;
2739		}
2740
2741		/**
2742		 * Initialize a Reed-Solomon codec and returns an array of values.
2743		 * @param int $symsize symbol size, bits
2744		 * @param int $gfpoly  Field generator polynomial coefficients
2745		 * @param int $fcr  first root of RS code generator polynomial, index form
2746		 * @param int $prim  primitive element to generate polynomial roots
2747		 * @param int $nroots RS code generator polynomial degree (number of roots)
2748		 * @param int $pad  padding bytes at front of shortened block
2749		 * @return array Array of RS values:<ul><li>mm = Bits per symbol;</li><li>nn = Symbols per block;</li><li>alpha_to = log lookup table array;</li><li>index_of = Antilog lookup table array;</li><li>genpoly = Generator polynomial array;</li><li>nroots = Number of generator;</li><li>roots = number of parity symbols;</li><li>fcr = First consecutive root, index form;</li><li>prim = Primitive element, index form;</li><li>iprim = prim-th root of 1, index form;</li><li>pad = Padding bytes in shortened block;</li><li>gfpoly</ul>.
2750		 */
2751		protected function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
2752			// Based on Reed solomon encoder by Phil Karn, KA9Q (GNU-LGPLv2)
2753			$rs = null;
2754			// Check parameter ranges
2755			if (($symsize < 0) OR ($symsize > 8)) {
2756				return $rs;
2757			}
2758			if (($fcr < 0) OR ($fcr >= (1<<$symsize))) {
2759				return $rs;
2760			}
2761			if (($prim <= 0) OR ($prim >= (1<<$symsize))) {
2762				return $rs;
2763			}
2764			if (($nroots < 0) OR ($nroots >= (1<<$symsize))) {
2765				return $rs;
2766			}
2767			if (($pad < 0) OR ($pad >= ((1<<$symsize) -1 - $nroots))) {
2768				return $rs;
2769			}
2770			$rs = array();
2771			$rs['mm'] = $symsize;
2772			$rs['nn'] = (1 << $symsize) - 1;
2773			$rs['pad'] = $pad;
2774			$rs['alpha_to'] = array_fill(0, ($rs['nn'] + 1), 0);
2775			$rs['index_of'] = array_fill(0, ($rs['nn'] + 1), 0);
2776			// PHP style macro replacement ;)
2777			$NN =& $rs['nn'];
2778			$A0 =& $NN;
2779			// Generate Galois field lookup tables
2780			$rs['index_of'][0] = $A0; // log(zero) = -inf
2781			$rs['alpha_to'][$A0] = 0; // alpha**-inf = 0
2782			$sr = 1;
2783			for ($i=0; $i<$rs['nn']; ++$i) {
2784				$rs['index_of'][$sr] = $i;
2785				$rs['alpha_to'][$i] = $sr;
2786				$sr <<= 1;
2787				if ($sr & (1 << $symsize)) {
2788					$sr ^= $gfpoly;
2789				}
2790				$sr &= $rs['nn'];
2791			}
2792			if ($sr != 1) {
2793				// field generator polynomial is not primitive!
2794				return NULL;
2795			}
2796			// Form RS code generator polynomial from its roots
2797			$rs['genpoly'] = array_fill(0, ($nroots + 1), 0);
2798			$rs['fcr'] = $fcr;
2799			$rs['prim'] = $prim;
2800			$rs['nroots'] = $nroots;
2801			$rs['gfpoly'] = $gfpoly;
2802			// Find prim-th root of 1, used in decoding
2803			for ($iprim=1; ($iprim % $prim) != 0; $iprim += $rs['nn']) {
2804				; // intentional empty-body loop!
2805			}
2806			$rs['iprim'] = (int)($iprim / $prim);
2807			$rs['genpoly'][0] = 1;
2808
2809
2810			for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
2811				$rs['genpoly'][$i+1] = 1;
2812				// Multiply rs->genpoly[] by  @**(root + x)
2813				for ($j = $i; $j > 0; --$j) {
2814					if ($rs['genpoly'][$j] != 0) {
2815						$rs['genpoly'][$j] = $rs['genpoly'][$j-1] ^ $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][$j]] + $root)];
2816					} else {
2817						$rs['genpoly'][$j] = $rs['genpoly'][$j-1];
2818					}
2819				}
2820				// rs->genpoly[0] can never be zero
2821				$rs['genpoly'][0] = $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][0]] + $root)];
2822			}
2823			// convert rs->genpoly[] to index form for quicker encoding
2824			for ($i = 0; $i <= $nroots; ++$i) {
2825				$rs['genpoly'][$i] = $rs['index_of'][$rs['genpoly'][$i]];
2826			}
2827			return $rs;
2828		}
2829
2830		/**
2831		 * Encode a Reed-Solomon codec and returns the parity array
2832		 * @param array $rs RS values
2833		 * @param array $data data
2834		 * @param array $parity parity
2835		 * @return parity array
2836		 */
2837		 protected function encode_rs_char($rs, $data, $parity) {
2838			$MM       =& $rs['mm']; // bits per symbol
2839			$NN       =& $rs['nn']; // the total number of symbols in a RS block
2840			$ALPHA_TO =& $rs['alpha_to']; // the address of an array of NN elements to convert Galois field elements in index (log) form to polynomial form
2841			$INDEX_OF =& $rs['index_of']; // the address of an array of NN elements to convert Galois field elements in polynomial form to index (log) form
2842			$GENPOLY  =& $rs['genpoly']; // an array of NROOTS+1 elements containing the generator polynomial in index form
2843			$NROOTS   =& $rs['nroots']; // the number of roots in the RS code generator polynomial, which is the same as the number of parity symbols in a block
2844			$FCR      =& $rs['fcr']; // first consecutive root, index form
2845			$PRIM     =& $rs['prim']; // primitive element, index form
2846			$IPRIM    =& $rs['iprim']; // prim-th root of 1, index form
2847			$PAD      =& $rs['pad']; // the number of pad symbols in a block
2848			$A0       =& $NN;
2849			$parity = array_fill(0, $NROOTS, 0);
2850			for ($i=0; $i < ($NN - $NROOTS - $PAD); $i++) {
2851				$feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
2852				if ($feedback != $A0) {
2853					// feedback term is non-zero
2854					// This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
2855					// always be for the polynomials constructed by init_rs()
2856					$feedback = $this->modnn($rs, $NN - $GENPOLY[$NROOTS] + $feedback);
2857					for ($j=1; $j < $NROOTS; ++$j) {
2858					$parity[$j] ^= $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[($NROOTS - $j)])];
2859					}
2860				}
2861				// Shift
2862				array_shift($parity);
2863				if ($feedback != $A0) {
2864					array_push($parity, $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[0])]);
2865				} else {
2866					array_push($parity, 0);
2867				}
2868			}
2869			return $parity;
2870		}
2871
2872	} // end QRcode class
2873
2874} // END OF "class_exists QRcode"
2875?>
2876