1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Class QRinputItem |
4
|
|
|
* @author Tinymeng <[email protected]> |
5
|
|
|
* @date: 2019/9/26 18:25 |
6
|
|
|
*/ |
7
|
|
|
namespace tinymeng\code\Gateways\qrcode; |
8
|
|
|
|
9
|
|
|
use Exception; |
10
|
|
|
|
11
|
|
|
class QRinputItem |
12
|
|
|
{ |
13
|
|
|
|
14
|
|
|
public $mode; |
15
|
|
|
public $size; |
16
|
|
|
public $data; |
17
|
|
|
public $bstream; |
18
|
|
|
|
19
|
|
|
public function __construct($mode, $size, $data, $bstream = null) |
20
|
|
|
{ |
21
|
|
|
$setData = array_slice($data, 0, $size); |
22
|
|
|
|
23
|
|
|
if (count($setData) < $size) { |
24
|
|
|
$setData = array_merge($setData, array_fill(0,$size-count($setData),0)); |
25
|
|
|
} |
26
|
|
|
|
27
|
|
|
if(!QRinput::check($mode, $size, $setData)) { |
28
|
|
|
throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData)); |
29
|
|
|
return null; |
|
|
|
|
30
|
|
|
} |
31
|
|
|
|
32
|
|
|
$this->mode = $mode; |
33
|
|
|
$this->size = $size; |
34
|
|
|
$this->data = $setData; |
35
|
|
|
$this->bstream = $bstream; |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
//---------------------------------------------------------------------- |
39
|
|
|
public function encodeModeNum($version) |
40
|
|
|
{ |
41
|
|
|
try { |
42
|
|
|
|
43
|
|
|
$words = (int)($this->size / 3); |
44
|
|
|
$bs = new QRbitstream(); |
45
|
|
|
|
46
|
|
|
$val = 0x1; |
47
|
|
|
$bs->appendNum(4, $val); |
48
|
|
|
$bs->appendNum(QRspec::lengthIndicator(QR_MODE_NUM, $version), $this->size); |
49
|
|
|
|
50
|
|
|
for($i=0; $i<$words; $i++) { |
51
|
|
|
$val = (ord($this->data[$i*3 ]) - ord('0')) * 100; |
52
|
|
|
$val += (ord($this->data[$i*3+1]) - ord('0')) * 10; |
53
|
|
|
$val += (ord($this->data[$i*3+2]) - ord('0')); |
54
|
|
|
$bs->appendNum(10, $val); |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
if($this->size - $words * 3 == 1) { |
58
|
|
|
$val = ord($this->data[$words*3]) - ord('0'); |
59
|
|
|
$bs->appendNum(4, $val); |
60
|
|
|
} else if($this->size - $words * 3 == 2) { |
61
|
|
|
$val = (ord($this->data[$words*3 ]) - ord('0')) * 10; |
62
|
|
|
$val += (ord($this->data[$words*3+1]) - ord('0')); |
63
|
|
|
$bs->appendNum(7, $val); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
$this->bstream = $bs; |
67
|
|
|
return 0; |
68
|
|
|
|
69
|
|
|
} catch (Exception $e) { |
70
|
|
|
return -1; |
71
|
|
|
} |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
//---------------------------------------------------------------------- |
75
|
|
|
public function encodeModeAn($version) |
76
|
|
|
{ |
77
|
|
|
try { |
78
|
|
|
$words = (int)($this->size / 2); |
79
|
|
|
$bs = new QRbitstream(); |
80
|
|
|
|
81
|
|
|
$bs->appendNum(4, 0x02); |
82
|
|
|
$bs->appendNum(QRspec::lengthIndicator(QR_MODE_AN, $version), $this->size); |
83
|
|
|
|
84
|
|
|
for($i=0; $i<$words; $i++) { |
85
|
|
|
$val = (int)QRinput::lookAnTable(ord($this->data[$i*2 ])) * 45; |
86
|
|
|
$val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1])); |
87
|
|
|
|
88
|
|
|
$bs->appendNum(11, $val); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
if($this->size & 1) { |
92
|
|
|
$val = QRinput::lookAnTable(ord($this->data[$words * 2])); |
93
|
|
|
$bs->appendNum(6, $val); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
$this->bstream = $bs; |
97
|
|
|
return 0; |
98
|
|
|
|
99
|
|
|
} catch (Exception $e) { |
100
|
|
|
return -1; |
101
|
|
|
} |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
//---------------------------------------------------------------------- |
105
|
|
|
public function encodeMode8($version) |
106
|
|
|
{ |
107
|
|
|
try { |
108
|
|
|
$bs = new QRbitstream(); |
109
|
|
|
|
110
|
|
|
$bs->appendNum(4, 0x4); |
111
|
|
|
$bs->appendNum(QRspec::lengthIndicator(QR_MODE_8, $version), $this->size); |
112
|
|
|
|
113
|
|
|
for($i=0; $i<$this->size; $i++) { |
114
|
|
|
$bs->appendNum(8, ord($this->data[$i])); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
$this->bstream = $bs; |
118
|
|
|
return 0; |
119
|
|
|
|
120
|
|
|
} catch (Exception $e) { |
121
|
|
|
return -1; |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
//---------------------------------------------------------------------- |
126
|
|
|
public function encodeModeKanji($version) |
127
|
|
|
{ |
128
|
|
|
try { |
129
|
|
|
|
130
|
|
|
$bs = new QRbitrtream(); |
|
|
|
|
131
|
|
|
|
132
|
|
|
$bs->appendNum(4, 0x8); |
133
|
|
|
$bs->appendNum(QRspec::lengthIndicator(QR_MODE_KANJI, $version), (int)($this->size / 2)); |
134
|
|
|
|
135
|
|
|
for($i=0; $i<$this->size; $i+=2) { |
136
|
|
|
$val = (ord($this->data[$i]) << 8) | ord($this->data[$i+1]); |
137
|
|
|
if($val <= 0x9ffc) { |
138
|
|
|
$val -= 0x8140; |
139
|
|
|
} else { |
140
|
|
|
$val -= 0xc140; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
$h = ($val >> 8) * 0xc0; |
144
|
|
|
$val = ($val & 0xff) + $h; |
145
|
|
|
|
146
|
|
|
$bs->appendNum(13, $val); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
$this->bstream = $bs; |
150
|
|
|
return 0; |
151
|
|
|
|
152
|
|
|
} catch (Exception $e) { |
153
|
|
|
return -1; |
154
|
|
|
} |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
//---------------------------------------------------------------------- |
158
|
|
|
public function encodeModeStructure() |
159
|
|
|
{ |
160
|
|
|
try { |
161
|
|
|
$bs = new QRbitstream(); |
162
|
|
|
|
163
|
|
|
$bs->appendNum(4, 0x03); |
164
|
|
|
$bs->appendNum(4, ord($this->data[1]) - 1); |
165
|
|
|
$bs->appendNum(4, ord($this->data[0]) - 1); |
166
|
|
|
$bs->appendNum(8, ord($this->data[2])); |
167
|
|
|
|
168
|
|
|
$this->bstream = $bs; |
169
|
|
|
return 0; |
170
|
|
|
|
171
|
|
|
} catch (Exception $e) { |
172
|
|
|
return -1; |
173
|
|
|
} |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
//---------------------------------------------------------------------- |
177
|
|
|
public function estimateBitStreamSizeOfEntry($version) |
178
|
|
|
{ |
179
|
|
|
$bits = 0; |
180
|
|
|
|
181
|
|
|
if($version == 0) |
182
|
|
|
$version = 1; |
183
|
|
|
|
184
|
|
|
switch($this->mode) { |
185
|
|
|
case QR_MODE_NUM: $bits = QRinput::estimateBitsModeNum($this->size); break; |
186
|
|
|
case QR_MODE_AN: $bits = QRinput::estimateBitsModeAn($this->size); break; |
187
|
|
|
case QR_MODE_8: $bits = QRinput::estimateBitsMode8($this->size); break; |
188
|
|
|
case QR_MODE_KANJI: $bits = QRinput::estimateBitsModeKanji($this->size);break; |
|
|
|
|
189
|
|
|
case QR_MODE_STRUCTURE: return STRUCTURE_HEADER_BITS; |
190
|
|
|
default: |
191
|
|
|
return 0; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
$l = QRspec::lengthIndicator($this->mode, $version); |
195
|
|
|
$m = 1 << $l; |
196
|
|
|
$num = (int)(($this->size + $m - 1) / $m); |
197
|
|
|
|
198
|
|
|
$bits += $num * (4 + $l); |
199
|
|
|
|
200
|
|
|
return $bits; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
//---------------------------------------------------------------------- |
204
|
|
|
public function encodeBitStream($version) |
205
|
|
|
{ |
206
|
|
|
try { |
207
|
|
|
|
208
|
|
|
unset($this->bstream); |
209
|
|
|
$words = QRspec::maximumWords($this->mode, $version); |
210
|
|
|
|
211
|
|
|
if($this->size > $words) { |
212
|
|
|
|
213
|
|
|
$st1 = new \QRinputItem($this->mode, $words, $this->data); |
|
|
|
|
214
|
|
|
$st2 = new QRinputItem($this->mode, $this->size - $words, array_slice($this->data, $words)); |
215
|
|
|
|
216
|
|
|
$st1->encodeBitStream($version); |
217
|
|
|
$st2->encodeBitStream($version); |
218
|
|
|
|
219
|
|
|
$this->bstream = new QRbitstream(); |
220
|
|
|
$this->bstream->append($st1->bstream); |
221
|
|
|
$this->bstream->append($st2->bstream); |
222
|
|
|
|
223
|
|
|
unset($st1); |
224
|
|
|
unset($st2); |
225
|
|
|
|
226
|
|
|
} else { |
227
|
|
|
|
228
|
|
|
$ret = 0; |
229
|
|
|
|
230
|
|
|
switch($this->mode) { |
231
|
|
|
case QR_MODE_NUM: $ret = $this->encodeModeNum($version); break; |
232
|
|
|
case QR_MODE_AN: $ret = $this->encodeModeAn($version); break; |
233
|
|
|
case QR_MODE_8: $ret = $this->encodeMode8($version); break; |
234
|
|
|
case QR_MODE_KANJI: $ret = $this->encodeModeKanji($version);break; |
235
|
|
|
case QR_MODE_STRUCTURE: $ret = $this->encodeModeStructure(); break; |
236
|
|
|
|
237
|
|
|
default: |
238
|
|
|
break; |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
if($ret < 0) |
242
|
|
|
return -1; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
return $this->bstream->size(); |
246
|
|
|
|
247
|
|
|
} catch (Exception $e) { |
248
|
|
|
return -1; |
249
|
|
|
} |
250
|
|
|
} |
251
|
|
|
} |
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.