Kanji.php 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. <?php
  2. /**
  3. * Class Kanji
  4. *
  5. * @filesource Kanji.php
  6. * @created 25.11.2015
  7. * @package chillerlan\QRCode\Data
  8. * @author Smiley <smiley@chillerlan.net>
  9. * @copyright 2015 Smiley
  10. * @license MIT
  11. */
  12. namespace chillerlan\QRCode\Data;
  13. use chillerlan\QRCode\Common\{BitBuffer, Mode};
  14. use function mb_convert_encoding, mb_detect_encoding, mb_strlen, ord, sprintf, strlen;
  15. /**
  16. * Kanji mode: double-byte characters from the Shift JIS character set
  17. *
  18. * ISO/IEC 18004:2000 Section 8.3.5
  19. * ISO/IEC 18004:2000 Section 8.4.5
  20. */
  21. final class Kanji extends QRDataModeAbstract{
  22. protected static int $datamode = Mode::DATA_KANJI;
  23. public function __construct(string $data){
  24. parent::__construct($data);
  25. /** @noinspection PhpFieldAssignmentTypeMismatchInspection */
  26. $this->data = mb_convert_encoding($this->data, 'SJIS', mb_detect_encoding($this->data));
  27. }
  28. /**
  29. * @inheritdoc
  30. */
  31. protected function getCharCount():int{
  32. return mb_strlen($this->data, 'SJIS');
  33. }
  34. /**
  35. * @inheritdoc
  36. */
  37. public function getLengthInBits():int{
  38. return $this->getCharCount() * 13;
  39. }
  40. /**
  41. * checks if a string qualifies as Kanji
  42. */
  43. public static function validateString(string $string):bool{
  44. $i = 0;
  45. $len = strlen($string);
  46. while($i + 1 < $len){
  47. $c = ((0xff & ord($string[$i])) << 8) | (0xff & ord($string[$i + 1]));
  48. if(!($c >= 0x8140 && $c <= 0x9FFC) && !($c >= 0xE040 && $c <= 0xEBBF)){
  49. return false;
  50. }
  51. $i += 2;
  52. }
  53. return $i >= $len;
  54. }
  55. /**
  56. * @inheritdoc
  57. *
  58. * @throws \chillerlan\QRCode\Data\QRCodeDataException on an illegal character occurence
  59. */
  60. public function write(BitBuffer $bitBuffer, int $versionNumber):void{
  61. $bitBuffer
  62. ->put($this::$datamode, 4)
  63. ->put($this->getCharCount(), Mode::getLengthBitsForVersion($this::$datamode, $versionNumber))
  64. ;
  65. $len = strlen($this->data);
  66. for($i = 0; $i + 1 < $len; $i += 2){
  67. $c = ((0xff & ord($this->data[$i])) << 8) | (0xff & ord($this->data[$i + 1]));
  68. if($c >= 0x8140 && $c <= 0x9FFC){
  69. $c -= 0x8140;
  70. }
  71. elseif($c >= 0xE040 && $c <= 0xEBBF){
  72. $c -= 0xC140;
  73. }
  74. else{
  75. throw new QRCodeDataException(sprintf('illegal char at %d [%d]', $i + 1, $c));
  76. }
  77. $bitBuffer->put(((($c >> 8) & 0xff) * 0xC0) + ($c & 0xff), 13);
  78. }
  79. if($i < $len){
  80. throw new QRCodeDataException(sprintf('illegal char at %d', $i + 1));
  81. }
  82. }
  83. }