Security update for permissions_by_term
[yaffs-website] / vendor / behat / transliterator / src / Behat / Transliterator / SyncTool.php
1 <?php
2
3 namespace Behat\Transliterator;
4
5 use RollingCurl\Request;
6 use RollingCurl\RollingCurl;
7 use Yaoi\Command;
8 use Yaoi\Command\Option;
9 use Yaoi\Http\Client;
10 use Yaoi\String\Lexer\Parsed;
11 use Yaoi\String\Lexer\Parser;
12 use Yaoi\String\Lexer\Renderer;
13 use Yaoi\String\Lexer\Token;
14 use Yaoi\String\StringValue;
15 use Yaoi\String\Parser as StringParser;
16
17 /**
18  * Tool for converting char tables for Behat/Transliterator from Perl to PHP
19  * @internal
20  */
21 class SyncTool extends Command
22 {
23     const LIB_VERSION = '1.27';
24
25     private $tokenizer;
26     private $renderer;
27     private $phpTable;
28     private $itemIndex;
29     private $nonQuestionBoxFound;
30     private $block;
31
32     public function __construct()
33     {
34         $escape = array(
35             '\\}' => '}',
36             '\\\\' => '\\',
37             '\\{' => '{',
38             '\\@' => '@',
39             '\\$' => '$',
40         );
41
42         $this->tokenizer = new Parser();
43         $this->tokenizer->addLineStopper('#');
44         $this->tokenizer->addQuote('qq{', '}', $escape);
45         $this->tokenizer->addQuote('q{', '}', $escape);
46         $this->tokenizer->addQuote('"', '"');
47         $this->tokenizer->addQuote("'", "'");
48         $this->tokenizer->addBracket('[', ']');
49         $this->tokenizer->addDelimiter(';');
50
51         $this->renderer = new Renderer();
52         $this->renderer
53             ->setBindKey('-~z', 'z~-')
54             ->strip('#')
55             ->keepBoundaries('[');
56     }
57
58     public static function setUpDefinition(\Yaoi\Command\Definition $definition, $options)
59     {
60         $definition->name = 'update-data';
61         $definition->description = 'Tool for converting char tables for Behat/Transliterator from Perl to PHP';
62     }
63
64     public function performAction()
65     {
66         $rollingCurl = new RollingCurl();
67
68         foreach ($this->getPerlTablesUrlList() as $url) {
69             $rollingCurl->get($url);
70         }
71
72         $rollingCurl->setCallback(function (Request $request, RollingCurl $rollingCurl) {
73             $this->response->addContent($request->getUrl());
74             $content = $request->getResponseText();
75             $this->parsePerlTable($content);
76         })
77             ->execute();
78     }
79
80     private function removePhpCharTable($phpFilePath, $reason)
81     {
82         $this->response->addContent($reason);
83         if (file_exists($phpFilePath)) {
84             if (unlink($phpFilePath)) {
85                 $this->response->success('Deleted');
86             } else {
87                 $this->response->error('Failed to delete');
88             }
89         } else {
90             $this->response->success('No PHP file, skipped');
91         }
92     }
93
94     private function pushItem($item)
95     {
96         if ($this->itemIndex >= 16) {
97             $this->phpTable = trim($this->phpTable);
98             $this->phpTable .= "\n";
99             $this->itemIndex = 0;
100         }
101         ++$this->itemIndex;
102
103         $item = new StringValue($item);
104         if ($item->starts('\x') || $item->starts('\n')) {
105             $this->phpTable .= '"' . $item . '", ';
106             $this->nonQuestionBoxFound = true;
107         } else {
108             // TODO check if this hack should be removed for chinese letters
109             if ($item->value === '[?] ') {
110                 $item->value = '[?]';
111             }
112             //
113
114             if ($item->value !== '[?]') {
115                 $this->nonQuestionBoxFound = true;
116             }
117
118             $this->phpTable .= "'" . str_replace(array('\\', '\''), array('\\\\', '\\\''), $item) . "', ";
119         }
120     }
121
122     private function tokenizePerlTable($content)
123     {
124         $tokens = $this->tokenizer->tokenize($content);
125
126         $expression = $this->renderer->getExpression($tokens);
127         $statement = $expression->getStatement();
128         /** @var Parsed[] $binds */
129         $binds = $expression->getBinds();
130
131         $parser = new StringParser($statement);
132         $block = (string)$parser->inner('$Text::Unidecode::Char[', ']');
133         if (!$block) {
134             throw new \Exception('Block not found');
135         }
136         $this->block = $this->renderer->getExpression($binds[$block])->getStatement();
137
138         $itemsBind = (string)$parser->inner('[', ']');
139
140         if (!$itemsBind) {
141             $items = array();
142         }
143         else {
144             $items = $binds[$itemsBind];
145         }
146
147         return $items;
148     }
149
150     private function parsePerlTable($content)
151     {
152         $items = $this->tokenizePerlTable($content);
153
154         $phpFilePath = __DIR__ . '/data/' . substr($this->block, 1) . '.php';
155         if (!$items) {
156             $this->removePhpCharTable($phpFilePath, 'Empty char table for block ' . $this->block);
157             return;
158         }
159
160         $this->phpTable = <<<PHP
161 <?php
162 \$UTF8_TO_ASCII[$this->block] = array(
163
164 PHP;
165
166         $itemsExpression = $this->renderer->getExpression($items);
167         $itemsStatement = $itemsExpression->getStatement();
168         $itemsBinds = $itemsExpression->getBinds();
169
170         $itemsStatement = explode(',', $itemsStatement);
171         $this->itemIndex = 0;
172         $this->nonQuestionBoxFound = false;
173         foreach ($itemsStatement as $item) {
174             $item = trim($item);
175             if (!$item) {
176                 break;
177             }
178
179             if (isset($itemsBinds[$item])) {
180                 /** @var Token $token */
181                 $token = $itemsBinds[$item];
182                 $item = $token->unEscapedContent;
183             }
184
185             $this->pushItem($item);
186         }
187
188         if ($this->nonQuestionBoxFound) {
189             $this->phpTable = trim($this->phpTable) . "\n" . ');' . "\n";
190             if (file_put_contents($phpFilePath, $this->phpTable)) {
191                 $this->response->success('Block ' . $this->block . ' converted to ' . $phpFilePath);
192             } else {
193                 $this->response->error('Failed to save ' . $phpFilePath);
194             }
195         } else {
196             $this->removePhpCharTable($phpFilePath, 'Block ' . $this->block . ' contains only [?]');
197         }
198
199     }
200
201     private function getPerlTablesUrlList()
202     {
203         $client = new Client();
204         $list = array();
205         $page = $client->fetch('http://cpansearch.perl.org/src/SBURKE/Text-Unidecode-' . self::LIB_VERSION . '/lib/Text/Unidecode/');
206         foreach (StringParser::create($page)->innerAll('.pm">', '</a>') as $xXXpm) {
207             $list[] = 'http://cpansearch.perl.org/src/SBURKE/Text-Unidecode-' . self::LIB_VERSION . '/lib/Text/Unidecode/'
208                 . $xXXpm;
209         }
210         return $list;
211     }
212 }
213