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