1111namespace chillerlan \QRCode \Data ;
1212
1313use chillerlan \QRCode \Common \{BitBuffer , Mode };
14- use function array_flip , ceil , intdiv , str_split ;
14+ use function ceil , intdiv , preg_match , strpos ;
1515
1616/**
1717 * Alphanumeric mode: 0 to 9, A to Z, space, $ % * + - . / :
@@ -24,18 +24,9 @@ final class AlphaNum extends QRDataModeAbstract{
2424 /**
2525 * ISO/IEC 18004:2000 Table 5
2626 *
27- * @var int[]
27+ * @var string
2828 */
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 $%*+-./: ' ;
3930
4031 /**
4132 * @inheritDoc
@@ -53,18 +44,7 @@ public function getLengthInBits():int{
5344 * @inheritDoc
5445 */
5546 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 );
6848 }
6949
7050 /**
@@ -80,12 +60,15 @@ public function write(BitBuffer $bitBuffer, int $versionNumber):QRDataModeInterf
8060
8161 // encode 2 characters in 11 bits
8262 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+ );
8467 }
8568
8669 // encode a remaining character in 6 bits
8770 if ($ i < $ len ){
88- $ bitBuffer ->put (self :: CHAR_TO_ORD [ $ this ->data [$ i ]] , 6 );
71+ $ bitBuffer ->put ($ this ->ord ( $ this -> data [$ i ]) , 6 );
8972 }
9073
9174 return $ this ;
@@ -97,19 +80,7 @@ public function write(BitBuffer $bitBuffer, int $versionNumber):QRDataModeInterf
9780 * @throws \chillerlan\QRCode\Data\QRCodeDataException
9881 */
9982 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 ));
11384 $ result = '' ;
11485 // Read two characters at a time
11586 while ($ length > 1 ){
@@ -118,9 +89,9 @@ public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):s
11889 throw new QRCodeDataException ('not enough bits available ' ); // @codeCoverageIgnore
11990 }
12091
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 );
12495 $ length -= 2 ;
12596 }
12697
@@ -130,10 +101,35 @@ public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):s
130101 throw new QRCodeDataException ('not enough bits available ' ); // @codeCoverageIgnore
131102 }
132103
133- $ result .= $ toAlphaNumericChar ($ bitBuffer ->read (6 ));
104+ $ result .= self :: chr ($ bitBuffer ->read (6 ));
134105 }
135106
136107 return $ result ;
137108 }
138109
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+
139135}
0 commit comments