11
11
namespace chillerlan \QRCode \Data ;
12
12
13
13
use chillerlan \QRCode \Common \{BitBuffer , Mode };
14
- use function array_flip , ceil , intdiv , str_split ;
14
+ use function ceil , intdiv , preg_match , strpos ;
15
15
16
16
/**
17
17
* Alphanumeric mode: 0 to 9, A to Z, space, $ % * + - . / :
@@ -24,18 +24,9 @@ final class AlphaNum extends QRDataModeAbstract{
24
24
/**
25
25
* ISO/IEC 18004:2000 Table 5
26
26
*
27
- * @var int[]
27
+ * @var string
28
28
*/
29
- private const CHAR_TO_ORD = [
30
- // phpcs:ignore
31
- '0 ' => 0 , '1 ' => 1 , '2 ' => 2 , '3 ' => 3 , '4 ' => 4 , '5 ' => 5 , '6 ' => 6 , '7 ' => 7 ,
32
- // phpcs:ignore
33
- '8 ' => 8 , '9 ' => 9 , 'A ' => 10 , 'B ' => 11 , 'C ' => 12 , 'D ' => 13 , 'E ' => 14 , 'F ' => 15 ,
34
- 'G ' => 16 , 'H ' => 17 , 'I ' => 18 , 'J ' => 19 , 'K ' => 20 , 'L ' => 21 , 'M ' => 22 , 'N ' => 23 ,
35
- 'O ' => 24 , 'P ' => 25 , 'Q ' => 26 , 'R ' => 27 , 'S ' => 28 , 'T ' => 29 , 'U ' => 30 , 'V ' => 31 ,
36
- 'W ' => 32 , 'X ' => 33 , 'Y ' => 34 , 'Z ' => 35 , ' ' => 36 , '$ ' => 37 , '% ' => 38 , '* ' => 39 ,
37
- '+ ' => 40 , '- ' => 41 , '. ' => 42 , '/ ' => 43 , ': ' => 44 ,
38
- ];
29
+ private const CHAR_MAP = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./: ' ;
39
30
40
31
/**
41
32
* @inheritDoc
@@ -53,18 +44,7 @@ public function getLengthInBits():int{
53
44
* @inheritDoc
54
45
*/
55
46
public static function validateString (string $ string ):bool {
56
-
57
- if ($ string === '' ){
58
- return false ;
59
- }
60
-
61
- foreach (str_split ($ string ) as $ chr ){
62
- if (!isset (self ::CHAR_TO_ORD [$ chr ])){
63
- return false ;
64
- }
65
- }
66
-
67
- return true ;
47
+ return (bool )preg_match ('/^[A-Z\d %$*+-.:\/]+$/ ' , $ string );
68
48
}
69
49
70
50
/**
@@ -80,12 +60,15 @@ public function write(BitBuffer $bitBuffer, int $versionNumber):QRDataModeInterf
80
60
81
61
// encode 2 characters in 11 bits
82
62
for ($ i = 0 ; ($ i + 1 ) < $ len ; $ i += 2 ){
83
- $ bitBuffer ->put ((self ::CHAR_TO_ORD [$ this ->data [$ i ]] * 45 + self ::CHAR_TO_ORD [$ this ->data [($ i + 1 )]]), 11 );
63
+ $ bitBuffer ->put (
64
+ ($ this ->ord ($ this ->data [$ i ]) * 45 + $ this ->ord ($ this ->data [($ i + 1 )])),
65
+ 11 ,
66
+ );
84
67
}
85
68
86
69
// encode a remaining character in 6 bits
87
70
if ($ i < $ len ){
88
- $ bitBuffer ->put (self :: CHAR_TO_ORD [ $ this ->data [$ i ]] , 6 );
71
+ $ bitBuffer ->put ($ this ->ord ( $ this -> data [$ i ]) , 6 );
89
72
}
90
73
91
74
return $ this ;
@@ -97,19 +80,7 @@ public function write(BitBuffer $bitBuffer, int $versionNumber):QRDataModeInterf
97
80
* @throws \chillerlan\QRCode\Data\QRCodeDataException
98
81
*/
99
82
public static function decodeSegment (BitBuffer $ bitBuffer , int $ versionNumber ):string {
100
- $ length = $ bitBuffer ->read (self ::getLengthBits ($ versionNumber ));
101
- $ charmap = array_flip (self ::CHAR_TO_ORD );
102
-
103
- // @todo
104
- $ toAlphaNumericChar = function (int $ ord ) use ($ charmap ):string {
105
-
106
- if (isset ($ charmap [$ ord ])){
107
- return $ charmap [$ ord ];
108
- }
109
-
110
- throw new QRCodeDataException ('invalid character value: ' .$ ord );
111
- };
112
-
83
+ $ length = $ bitBuffer ->read (self ::getLengthBits ($ versionNumber ));
113
84
$ result = '' ;
114
85
// Read two characters at a time
115
86
while ($ length > 1 ){
@@ -118,9 +89,9 @@ public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):s
118
89
throw new QRCodeDataException ('not enough bits available ' ); // @codeCoverageIgnore
119
90
}
120
91
121
- $ nextTwoCharsBits = $ bitBuffer ->read (11 );
122
- $ result .= $ toAlphaNumericChar (intdiv ($ nextTwoCharsBits , 45 ));
123
- $ result .= $ toAlphaNumericChar ($ nextTwoCharsBits % 45 );
92
+ $ nextTwoCharsBits = $ bitBuffer ->read (11 );
93
+ $ result .= self :: chr (intdiv ($ nextTwoCharsBits , 45 ));
94
+ $ result .= self :: chr ($ nextTwoCharsBits % 45 );
124
95
$ length -= 2 ;
125
96
}
126
97
@@ -130,10 +101,35 @@ public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):s
130
101
throw new QRCodeDataException ('not enough bits available ' ); // @codeCoverageIgnore
131
102
}
132
103
133
- $ result .= $ toAlphaNumericChar ($ bitBuffer ->read (6 ));
104
+ $ result .= self :: chr ($ bitBuffer ->read (6 ));
134
105
}
135
106
136
107
return $ result ;
137
108
}
138
109
110
+ /**
111
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
112
+ */
113
+ private function ord (string $ chr ):int {
114
+ $ ord = strpos (self ::CHAR_MAP , $ chr );
115
+
116
+ if ($ ord === false ){
117
+ throw new QRCodeDataException ('invalid character ' ); // @codeCoverageIgnore
118
+ }
119
+
120
+ return $ ord ;
121
+ }
122
+
123
+ /**
124
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
125
+ */
126
+ private static function chr (int $ ord ):string {
127
+
128
+ if ($ ord < 0 || $ ord > 44 ){
129
+ throw new QRCodeDataException ('invalid character code ' ); // @codeCoverageIgnore
130
+ }
131
+
132
+ return self ::CHAR_MAP [$ ord ];
133
+ }
134
+
139
135
}
0 commit comments