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