PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.36.0
MailPoet – Newsletters, Email Marketing, and Automation v5.36.0
5.36.0 5.35.1 5.35.0 5.34.3 5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / vendor-prefixed / cerdic / css-tidy / class.csstidy.php
mailpoet / vendor-prefixed / cerdic / css-tidy Last commit date
class.csstidy.php 3 years ago class.csstidy_optimise.php 2 years ago class.csstidy_print.php 3 years ago cssparse.css 4 years ago cssparsed.css 4 years ago data.inc.php 4 years ago index.php 3 years ago lang.inc.php 4 years ago template.tpl 4 years ago template1.tpl 4 years ago template2.tpl 4 years ago template3.tpl 4 years ago
class.csstidy.php
821 lines
1 <?php
2 namespace MailPoetVendor;
3 if (!defined('ABSPATH')) exit;
4 \define('AT_START', 1);
5 \define('AT_END', 2);
6 \define('SEL_START', 3);
7 \define('SEL_END', 4);
8 \define('PROPERTY', 5);
9 \define('VALUE', 6);
10 \define('COMMENT', 7);
11 \define('IMPORTANT_COMMENT', 8);
12 \define('DEFAULT_AT', 41);
13 require __DIR__ . \DIRECTORY_SEPARATOR . 'class.csstidy_print.php';
14 require __DIR__ . \DIRECTORY_SEPARATOR . 'class.csstidy_optimise.php';
15 class csstidy
16 {
17 public $css = array();
18 public $tokens = array();
19 public $print;
20 public $optimise;
21 public $charset = '';
22 public $import = array();
23 public $namespace = '';
24 public $version = '2.0.3';
25 public $settings = array();
26 public $status = 'is';
27 public $at = '';
28 public $next_selector_at = '';
29 public $selector = '';
30 public $property = '';
31 public $sel_separate = array();
32 public $value = '';
33 public $sub_value = '';
34 public $sub_value_arr = array();
35 public $str_char = array();
36 public $cur_string = array();
37 public $from = array();
38 public $invalid_at = \false;
39 public $added = \false;
40 public $log = array();
41 public $line = 1;
42 public $quoted_string = array();
43 public $tokens_list = "";
44 public $data = array();
45 public $template;
46 public function __construct()
47 {
48 $data = array();
49 include __DIR__ . \DIRECTORY_SEPARATOR . 'data.inc.php';
50 $this->data = $data;
51 $this->settings['remove_bslash'] = \true;
52 $this->settings['compress_colors'] = \true;
53 $this->settings['compress_font-weight'] = \true;
54 $this->settings['lowercase_s'] = \false;
55 $this->settings['optimise_shorthands'] = 1;
56 $this->settings['remove_last_;'] = \true;
57 $this->settings['space_before_important'] = \false;
58 $this->settings['case_properties'] = 1;
59 $this->settings['sort_properties'] = \false;
60 $this->settings['sort_selectors'] = 0;
61 $this->settings['merge_selectors'] = 0;
62 $this->settings['reverse_left_and_right'] = 0;
63 $this->settings['discard_invalid_selectors'] = \false;
64 $this->settings['discard_invalid_properties'] = \false;
65 $this->settings['css_level'] = 'CSS3.0';
66 $this->settings['preserve_css'] = \false;
67 $this->settings['timestamp'] = \false;
68 $this->settings['template'] = '';
69 // say that propertie exist
70 $this->set_cfg('template', 'default');
71 // call load_template
72 $this->optimise = new csstidy_optimise($this);
73 $this->tokens_list =& $this->data['csstidy']['tokens'];
74 }
75 public function get_cfg($setting)
76 {
77 if (isset($this->settings[$setting])) {
78 return $this->settings[$setting];
79 }
80 return \false;
81 }
82 public function _load_template($template)
83 {
84 switch ($template) {
85 case 'default':
86 $this->load_template('default');
87 break;
88 case 'highest':
89 $this->load_template('highest_compression');
90 break;
91 case 'high':
92 $this->load_template('high_compression');
93 break;
94 case 'low':
95 $this->load_template('low_compression');
96 break;
97 default:
98 $this->load_template($template);
99 break;
100 }
101 }
102 public function set_cfg($setting, $value = null)
103 {
104 if (\is_array($setting) && $value === null) {
105 foreach ($setting as $setprop => $setval) {
106 $this->settings[$setprop] = $setval;
107 }
108 if (\array_key_exists('template', $setting)) {
109 $this->_load_template($this->settings['template']);
110 }
111 return \true;
112 } elseif (isset($this->settings[$setting]) && $value !== '') {
113 $this->settings[$setting] = $value;
114 if ($setting === 'template') {
115 $this->_load_template($this->settings['template']);
116 }
117 return \true;
118 }
119 return \false;
120 }
121 public function _add_token($type, $data, $do = \false)
122 {
123 if ($this->get_cfg('preserve_css') || $do) {
124 // nested @... : if opening a new part we just closed, remove the previous closing instead of adding opening
125 if ($type === \AT_START and \count($this->tokens) and $last = \end($this->tokens) and $last[0] === \AT_END and $last[1] === \trim($data)) {
126 \array_pop($this->tokens);
127 } else {
128 $this->tokens[] = array($type, ($type == \COMMENT or $type == \IMPORTANT_COMMENT) ? $data : \trim($data));
129 }
130 }
131 }
132 public function log($message, $type, $line = -1)
133 {
134 if ($line === -1) {
135 $line = $this->line;
136 }
137 $line = \intval($line);
138 $add = array('m' => $message, 't' => $type);
139 if (!isset($this->log[$line]) || !\in_array($add, $this->log[$line])) {
140 $this->log[$line][] = $add;
141 }
142 }
143 public function _unicode(&$string, &$i)
144 {
145 ++$i;
146 $add = '';
147 $replaced = \false;
148 while ($i < \strlen($string) && (\ctype_xdigit($string[$i]) || \ctype_space($string[$i])) && \strlen($add) < 6) {
149 $add .= $string[$i];
150 if (\ctype_space($string[$i])) {
151 break;
152 }
153 $i++;
154 }
155 if (\hexdec($add) > 47 && \hexdec($add) < 58 || \hexdec($add) > 64 && \hexdec($add) < 91 || \hexdec($add) > 96 && \hexdec($add) < 123) {
156 $this->log('Replaced unicode notation: Changed \\' . $add . ' to ' . \chr(\hexdec($add)), 'Information');
157 $add = \chr(\hexdec($add));
158 $replaced = \true;
159 } else {
160 $add = \trim('\\' . $add);
161 }
162 if (@\ctype_xdigit($string[$i + 1]) && \ctype_space($string[$i]) && !$replaced || !\ctype_space($string[$i])) {
163 $i--;
164 }
165 if ($add !== '\\' || !$this->get_cfg('remove_bslash') || \strpos($this->tokens_list, $string[$i + 1]) !== \false) {
166 return $add;
167 }
168 if ($add === '\\') {
169 $this->log('Removed unnecessary backslash', 'Information');
170 }
171 return '';
172 }
173 public function write_page($filename, $doctype = 'xhtml1.1', $externalcss = \true, $title = '', $lang = 'en')
174 {
175 $this->write($filename, \true);
176 }
177 public function write($filename, $formatted = \false, $doctype = 'xhtml1.1', $externalcss = \true, $title = '', $lang = 'en', $pre_code = \true)
178 {
179 $filename .= $formatted ? '.xhtml' : '.css';
180 if (!\is_dir('temp')) {
181 $madedir = \mkdir('temp');
182 if (!$madedir) {
183 print 'Could not make directory "temp" in ' . \dirname(__FILE__);
184 exit;
185 }
186 }
187 $handle = \fopen('temp/' . $filename, 'w');
188 if ($handle) {
189 if (!$formatted) {
190 \fwrite($handle, $this->print->plain());
191 } else {
192 \fwrite($handle, $this->print->formatted_page($doctype, $externalcss, $title, $lang, $pre_code));
193 }
194 }
195 \fclose($handle);
196 }
197 public function load_template($content, $from_file = \true)
198 {
199 $predefined_templates =& $this->data['csstidy']['predefined_templates'];
200 if ($content === 'high_compression' || $content === 'default' || $content === 'highest_compression' || $content === 'low_compression') {
201 $this->template = $predefined_templates[$content];
202 return;
203 }
204 if ($from_file) {
205 $content = \strip_tags(\file_get_contents($content), '<span>');
206 }
207 $content = \str_replace("\r\n", "\n", $content);
208 // Unify newlines (because the output also only uses \n)
209 $template = \explode('|', $content);
210 for ($i = 0; $i < \count($template); $i++) {
211 $this->template[$i] = $template[$i];
212 }
213 }
214 public function parse_from_url($url)
215 {
216 return $this->parse(@\file_get_contents($url));
217 }
218 public function is_token(&$string, $i)
219 {
220 return \strpos($this->tokens_list, $string[$i]) !== \false && !$this->escaped($string, $i);
221 }
222 public function parse($string)
223 {
224 // Temporarily set locale to en_US in order to handle floats properly
225 $old = @\setlocale(\LC_ALL, 0);
226 @\setlocale(\LC_ALL, 'C');
227 // PHP bug? Settings need to be refreshed in PHP4
228 $this->print = new csstidy_print($this);
229 $this->optimise = new csstidy_optimise($this);
230 $all_properties =& $this->data['csstidy']['all_properties'];
231 $at_rules =& $this->data['csstidy']['at_rules'];
232 $quoted_string_properties =& $this->data['csstidy']['quoted_string_properties'];
233 $this->css = array();
234 $this->print->input_css = $string;
235 $string = \str_replace("\r\n", "\n", $string) . ' ';
236 $cur_comment = '';
237 $cur_at = '';
238 for ($i = 0, $size = \strlen($string); $i < $size; $i++) {
239 if ($string[$i] === "\n" || $string[$i] === "\r") {
240 ++$this->line;
241 }
242 switch ($this->status) {
243 case 'at':
244 if ($this->is_token($string, $i)) {
245 if ($string[$i] === '/' && @$string[$i + 1] === '*') {
246 $this->status = 'ic';
247 ++$i;
248 $this->from[] = 'at';
249 } elseif ($string[$i] === '{') {
250 $this->status = 'is';
251 $this->at = $this->css_new_media_section($this->at, $cur_at);
252 $this->_add_token(\AT_START, $this->at);
253 } elseif ($string[$i] === ',') {
254 $cur_at = \trim($cur_at) . ',';
255 } elseif ($string[$i] === '\\') {
256 $cur_at .= $this->_unicode($string, $i);
257 } elseif (\in_array($string[$i], array('(', ')', ':', '.', '/'))) {
258 $cur_at .= $string[$i];
259 }
260 } else {
261 $lastpos = \strlen($cur_at) - 1;
262 if (!((\ctype_space($cur_at[$lastpos]) || $this->is_token($cur_at, $lastpos) && $cur_at[$lastpos] === ',') && \ctype_space($string[$i]))) {
263 $cur_at .= $string[$i];
264 }
265 }
266 break;
267 case 'is':
268 if ($this->is_token($string, $i)) {
269 if ($string[$i] === '/' && @$string[$i + 1] === '*' && \trim($this->selector) == '') {
270 $this->status = 'ic';
271 ++$i;
272 $this->from[] = 'is';
273 } elseif ($string[$i] === '@' && \trim($this->selector) == '') {
274 // Check for at-rule
275 $this->invalid_at = \true;
276 foreach ($at_rules as $name => $type) {
277 if (!\strcasecmp(\substr($string, $i + 1, \strlen($name)), $name)) {
278 $type === 'at' ? $cur_at = '@' . $name : ($this->selector = '@' . $name);
279 if ($type === 'atis') {
280 $this->next_selector_at = $this->next_selector_at ? $this->next_selector_at : ($this->at ? $this->at : \DEFAULT_AT);
281 $this->at = $this->css_new_media_section($this->at, ' ', \true);
282 $type = 'is';
283 }
284 $this->status = $type;
285 $i += \strlen($name);
286 $this->invalid_at = \false;
287 break;
288 }
289 }
290 if ($this->invalid_at) {
291 $this->selector = '@';
292 $invalid_at_name = '';
293 for ($j = $i + 1; $j < $size; ++$j) {
294 if (!\ctype_alpha($string[$j])) {
295 break;
296 }
297 $invalid_at_name .= $string[$j];
298 }
299 $this->log('Invalid @-rule: ' . $invalid_at_name . ' (removed)', 'Warning');
300 }
301 } elseif ($string[$i] === '"' || $string[$i] === "'") {
302 $this->cur_string[] = $string[$i];
303 $this->status = 'instr';
304 $this->str_char[] = $string[$i];
305 $this->from[] = 'is';
306 $this->quoted_string[] = $string[$i - 1] === '=';
307 } elseif ($this->invalid_at && $string[$i] === ';') {
308 $this->invalid_at = \false;
309 $this->status = 'is';
310 if ($this->next_selector_at) {
311 $this->at = $this->css_close_media_section($this->at);
312 $this->at = $this->css_new_media_section($this->at, $this->next_selector_at);
313 $this->next_selector_at = '';
314 }
315 } elseif ($string[$i] === '{') {
316 $this->status = 'ip';
317 if ($this->at == '') {
318 $this->at = $this->css_new_media_section($this->at, \DEFAULT_AT);
319 }
320 $this->selector = $this->css_new_selector($this->at, $this->selector);
321 $this->_add_token(\SEL_START, $this->selector);
322 $this->added = \false;
323 } elseif ($string[$i] === '}') {
324 $this->_add_token(\AT_END, $this->at);
325 $this->at = $this->css_close_media_section($this->at);
326 $this->selector = '';
327 $this->sel_separate = array();
328 } elseif ($string[$i] === ',') {
329 $this->selector = \trim($this->selector) . ',';
330 $this->sel_separate[] = \strlen($this->selector);
331 } elseif ($string[$i] === '\\') {
332 $this->selector .= $this->_unicode($string, $i);
333 } elseif ($string[$i] === '*' && @\in_array($string[$i + 1], array('.', '#', '[', ':')) && ($i == 0 or $string[$i - 1] !== '/')) {
334 // remove unnecessary universal selector, FS#147, but not comment in selector
335 } else {
336 $this->selector .= $string[$i];
337 }
338 } else {
339 $lastpos = \strlen($this->selector) - 1;
340 if ($lastpos == -1 || !((\ctype_space($this->selector[$lastpos]) || $this->is_token($this->selector, $lastpos) && $this->selector[$lastpos] === ',') && \ctype_space($string[$i]))) {
341 $this->selector .= $string[$i];
342 }
343 }
344 break;
345 case 'ip':
346 if ($this->is_token($string, $i)) {
347 if (($string[$i] === ':' || $string[$i] === '=') && $this->property != '') {
348 $this->status = 'iv';
349 if (!$this->get_cfg('discard_invalid_properties') || $this->property_is_valid($this->property)) {
350 $this->property = $this->css_new_property($this->at, $this->selector, $this->property);
351 $this->_add_token(\PROPERTY, $this->property);
352 }
353 } elseif ($string[$i] === '/' && @$string[$i + 1] === '*' && $this->property == '') {
354 $this->status = 'ic';
355 ++$i;
356 $this->from[] = 'ip';
357 } elseif ($string[$i] === '}') {
358 $this->explode_selectors();
359 $this->status = 'is';
360 $this->invalid_at = \false;
361 $this->_add_token(\SEL_END, $this->selector);
362 $this->selector = '';
363 $this->property = '';
364 if ($this->next_selector_at) {
365 $this->at = $this->css_close_media_section($this->at);
366 $this->at = $this->css_new_media_section($this->at, $this->next_selector_at);
367 $this->next_selector_at = '';
368 }
369 } elseif ($string[$i] === ';') {
370 $this->property = '';
371 } elseif ($string[$i] === '\\') {
372 $this->property .= $this->_unicode($string, $i);
373 } elseif ($this->property === '' && !\ctype_space($string[$i]) || ($this->property === '/' || $string[$i] === '/')) {
374 $this->property .= $string[$i];
375 }
376 } elseif (!\ctype_space($string[$i])) {
377 $this->property .= $string[$i];
378 }
379 break;
380 case 'iv':
381 $pn = ($string[$i] === "\n" || $string[$i] === "\r") && $this->property_is_next($string, $i + 1) || $i == \strlen($string) - 1;
382 if ($this->is_token($string, $i) || $pn) {
383 if ($string[$i] === '/' && @$string[$i + 1] === '*') {
384 $this->status = 'ic';
385 ++$i;
386 $this->from[] = 'iv';
387 } elseif ($string[$i] === '"' || $string[$i] === "'" || $string[$i] === '(') {
388 $this->cur_string[] = $string[$i];
389 $this->str_char[] = $string[$i] === '(' ? ')' : $string[$i];
390 $this->status = 'instr';
391 $this->from[] = 'iv';
392 $this->quoted_string[] = \in_array(\strtolower($this->property), $quoted_string_properties);
393 } elseif ($string[$i] === ',') {
394 $this->sub_value = \trim($this->sub_value) . ',';
395 } elseif ($string[$i] === '\\') {
396 $this->sub_value .= $this->_unicode($string, $i);
397 } elseif ($string[$i] === ';' || $pn) {
398 if ($this->selector[0] === '@' && isset($at_rules[\substr($this->selector, 1)]) && $at_rules[\substr($this->selector, 1)] === 'iv') {
399 $this->sub_value_arr[] = \trim($this->sub_value);
400 $this->status = 'is';
401 switch ($this->selector) {
402 case '@charset':
403 $this->charset = '"' . $this->sub_value_arr[0] . '"';
404 break;
405 case '@namespace':
406 $this->namespace = \implode(' ', $this->sub_value_arr);
407 break;
408 case '@import':
409 $this->import[] = \implode(' ', $this->sub_value_arr);
410 break;
411 }
412 $this->sub_value_arr = array();
413 $this->sub_value = '';
414 $this->selector = '';
415 $this->sel_separate = array();
416 } else {
417 $this->status = 'ip';
418 }
419 } elseif ($string[$i] !== '}') {
420 $this->sub_value .= $string[$i];
421 }
422 if (($string[$i] === '}' || $string[$i] === ';' || $pn) && !empty($this->selector)) {
423 if ($this->at == '') {
424 $this->at = $this->css_new_media_section($this->at, \DEFAULT_AT);
425 }
426 // case settings
427 if ($this->get_cfg('lowercase_s')) {
428 $this->selector = \strtolower($this->selector);
429 }
430 $this->property = \strtolower($this->property);
431 $this->optimise->subvalue();
432 if ($this->sub_value != '') {
433 $this->sub_value_arr[] = $this->sub_value;
434 $this->sub_value = '';
435 }
436 $this->value = '';
437 while (\count($this->sub_value_arr)) {
438 $sub = \array_shift($this->sub_value_arr);
439 if (\strstr($this->selector, 'font-face')) {
440 $sub = $this->quote_font_format($sub);
441 }
442 if ($sub != '') {
443 $this->value .= (!\strlen($this->value) || \substr($this->value, -1, 1) === ',' ? '' : ' ') . $sub;
444 }
445 }
446 $this->optimise->value();
447 $valid = $this->property_is_valid($this->property);
448 if ((!$this->invalid_at || $this->get_cfg('preserve_css')) && (!$this->get_cfg('discard_invalid_properties') || $valid)) {
449 $this->css_add_property($this->at, $this->selector, $this->property, $this->value);
450 $this->_add_token(\VALUE, $this->value);
451 $this->optimise->shorthands();
452 }
453 if (!$valid) {
454 if ($this->get_cfg('discard_invalid_properties')) {
455 $this->log('Removed invalid property: ' . $this->property, 'Warning');
456 } else {
457 $this->log('Invalid property in ' . \strtoupper($this->get_cfg('css_level')) . ': ' . $this->property, 'Warning');
458 }
459 }
460 $this->property = '';
461 $this->sub_value_arr = array();
462 $this->value = '';
463 }
464 if ($string[$i] === '}') {
465 $this->explode_selectors();
466 $this->_add_token(\SEL_END, $this->selector);
467 $this->status = 'is';
468 $this->invalid_at = \false;
469 $this->selector = '';
470 if ($this->next_selector_at) {
471 $this->at = $this->css_close_media_section($this->at);
472 $this->at = $this->css_new_media_section($this->at, $this->next_selector_at);
473 $this->next_selector_at = '';
474 }
475 }
476 } elseif (!$pn) {
477 $this->sub_value .= $string[$i];
478 if (\ctype_space($string[$i])) {
479 $this->optimise->subvalue();
480 if ($this->sub_value != '') {
481 $this->sub_value_arr[] = $this->sub_value;
482 $this->sub_value = '';
483 }
484 }
485 }
486 break;
487 case 'instr':
488 $_str_char = $this->str_char[\count($this->str_char) - 1];
489 $_cur_string = $this->cur_string[\count($this->cur_string) - 1];
490 $_quoted_string = $this->quoted_string[\count($this->quoted_string) - 1];
491 $temp_add = $string[$i];
492 // Add another string to the stack. Strings can't be nested inside of quotes, only parentheses, but
493 // parentheticals can be nested more than once.
494 if ($_str_char === ")" && ($string[$i] === "(" || $string[$i] === '"' || $string[$i] === '\'') && !$this->escaped($string, $i)) {
495 $this->cur_string[] = $string[$i];
496 $this->str_char[] = $string[$i] === '(' ? ')' : $string[$i];
497 $this->from[] = 'instr';
498 $this->quoted_string[] = $_str_char === ')' && $string[$i] !== '(' && \trim($_cur_string) === '(' ? $_quoted_string : !($string[$i] === '(');
499 continue 2;
500 }
501 if ($_str_char !== ")" && ($string[$i] === "\n" || $string[$i] === "\r") && !($string[$i - 1] === '\\' && !$this->escaped($string, $i - 1))) {
502 $temp_add = "\\A";
503 $this->log('Fixed incorrect newline in string', 'Warning');
504 }
505 $_cur_string .= $temp_add;
506 if ($string[$i] === $_str_char && !$this->escaped($string, $i)) {
507 $this->status = \array_pop($this->from);
508 if (!\preg_match('|[' . \implode('', $this->data['csstidy']['whitespace']) . ']|uis', $_cur_string) && $this->property !== 'content') {
509 if (!$_quoted_string) {
510 if ($_str_char !== ')') {
511 // Convert properties like
512 // font-family: 'Arial';
513 // to
514 // font-family: Arial;
515 // or
516 // url("abc")
517 // to
518 // url(abc)
519 $_cur_string = \substr($_cur_string, 1, -1);
520 }
521 } else {
522 $_quoted_string = \false;
523 }
524 }
525 \array_pop($this->cur_string);
526 \array_pop($this->quoted_string);
527 \array_pop($this->str_char);
528 if ($_str_char === ')') {
529 $_cur_string = '(' . \trim(\substr($_cur_string, 1, -1)) . ')';
530 }
531 if ($this->status === 'iv') {
532 if (!$_quoted_string) {
533 if (\strpos($_cur_string, ',') !== \false) {
534 // we can on only remove space next to ','
535 $_cur_string = \implode(',', \array_map('trim', \explode(',', $_cur_string)));
536 }
537 // and multiple spaces (too expensive)
538 if (\strpos($_cur_string, ' ') !== \false) {
539 $_cur_string = \preg_replace(",\\s+,", ' ', $_cur_string);
540 }
541 }
542 $this->sub_value .= $_cur_string;
543 } elseif ($this->status === 'is') {
544 $this->selector .= $_cur_string;
545 } elseif ($this->status === 'instr') {
546 $this->cur_string[\count($this->cur_string) - 1] .= $_cur_string;
547 }
548 } else {
549 $this->cur_string[\count($this->cur_string) - 1] = $_cur_string;
550 }
551 break;
552 case 'ic':
553 if ($string[$i] === '*' && $string[$i + 1] === '/') {
554 $this->status = \array_pop($this->from);
555 $i++;
556 if (\strlen($cur_comment) > 1 and \strncmp($cur_comment, '!', 1) === 0) {
557 $this->_add_token(\IMPORTANT_COMMENT, $cur_comment);
558 $this->css_add_important_comment($cur_comment);
559 } else {
560 $this->_add_token(\COMMENT, $cur_comment);
561 }
562 $cur_comment = '';
563 } else {
564 $cur_comment .= $string[$i];
565 }
566 break;
567 }
568 }
569 $this->optimise->postparse();
570 $this->print->_reset();
571 @\setlocale(\LC_ALL, $old);
572 // Set locale back to original setting
573 return !(empty($this->css) && empty($this->import) && empty($this->charset) && empty($this->tokens) && empty($this->namespace));
574 }
575 public function quote_font_format($value)
576 {
577 if (\strncmp($value, 'format', 6) == 0) {
578 $p = \strpos($value, ')', 7);
579 $end = \substr($value, $p);
580 $format_strings = $this->parse_string_list(\substr($value, 7, $p - 7));
581 if (!$format_strings) {
582 $value = '';
583 } else {
584 $value = 'format(';
585 foreach ($format_strings as $format_string) {
586 $value .= '"' . \str_replace('"', '\\"', $format_string) . '",';
587 }
588 $value = \substr($value, 0, -1) . $end;
589 }
590 }
591 return $value;
592 }
593 public function explode_selectors()
594 {
595 // Explode multiple selectors
596 if ($this->get_cfg('merge_selectors') === 1) {
597 $new_sels = array();
598 $lastpos = 0;
599 $this->sel_separate[] = \strlen($this->selector);
600 foreach ($this->sel_separate as $num => $pos) {
601 if ($num == \count($this->sel_separate) - 1) {
602 $pos += 1;
603 }
604 $new_sels[] = \substr($this->selector, $lastpos, $pos - $lastpos - 1);
605 $lastpos = $pos;
606 }
607 if (\count($new_sels) > 1) {
608 foreach ($new_sels as $selector) {
609 if (isset($this->css[$this->at][$this->selector])) {
610 $this->merge_css_blocks($this->at, $selector, $this->css[$this->at][$this->selector]);
611 }
612 }
613 unset($this->css[$this->at][$this->selector]);
614 }
615 }
616 $this->sel_separate = array();
617 }
618 static function escaped(&$string, $pos)
619 {
620 return !(@($string[$pos - 1] !== '\\') || csstidy::escaped($string, $pos - 1));
621 }
622 public function css_add_important_comment($comment)
623 {
624 if ($this->get_cfg('preserve_css') || \trim($comment) == '') {
625 return;
626 }
627 if (!isset($this->css['!'])) {
628 $this->css['!'] = '';
629 } else {
630 $this->css['!'] .= "\n";
631 }
632 $this->css['!'] .= $comment;
633 }
634 public function css_add_property($media, $selector, $property, $new_val)
635 {
636 if ($this->get_cfg('preserve_css') || \trim($new_val) == '') {
637 return;
638 }
639 $this->added = \true;
640 if (isset($this->css[$media][$selector][$property])) {
641 if ($this->is_important($this->css[$media][$selector][$property]) && $this->is_important($new_val) || !$this->is_important($this->css[$media][$selector][$property])) {
642 $this->css[$media][$selector][$property] = \trim($new_val);
643 }
644 } else {
645 $this->css[$media][$selector][$property] = \trim($new_val);
646 }
647 }
648 public function css_check_last_media_section_or_inc($media)
649 {
650 // are we starting?
651 if (!$this->css || !\is_array($this->css) || empty($this->css)) {
652 return $media;
653 }
654 // if the last @media is the same as this
655 // keep it
656 \end($this->css);
657 $at = \key($this->css);
658 if ($at == $media) {
659 return $media;
660 }
661 // else inc the section in the array
662 while (isset($this->css[$media])) {
663 if (\is_numeric($media)) {
664 $media++;
665 } else {
666 $media .= ' ';
667 }
668 }
669 return $media;
670 }
671 public function css_new_media_section($current_media, $new_media, $at_root = \false)
672 {
673 if ($this->get_cfg('preserve_css')) {
674 return $new_media;
675 }
676 // if we already are in a media and CSS level is 3, manage nested medias
677 if ($current_media && !$at_root && !\is_numeric($current_media) && \strncmp($this->get_cfg('css_level'), 'CSS3', 4) == 0) {
678 $new_media = \rtrim($current_media) . "{" . \rtrim($new_media);
679 }
680 return $this->css_check_last_media_section_or_inc($new_media);
681 }
682 public function css_close_media_section($current_media)
683 {
684 if ($this->get_cfg('preserve_css')) {
685 return '';
686 }
687 if (\strpos($current_media, '{') !== \false) {
688 $current_media = \explode('{', $current_media);
689 \array_pop($current_media);
690 $current_media = \implode('{', $current_media);
691 return $current_media;
692 }
693 return '';
694 }
695 public function css_new_selector($media, $selector)
696 {
697 if ($this->get_cfg('preserve_css')) {
698 return $selector;
699 }
700 $selector = \trim($selector);
701 if (\strncmp($selector, '@font-face', 10) != 0) {
702 if ($this->settings['merge_selectors'] != \false) {
703 return $selector;
704 }
705 if (!$this->css || !isset($this->css[$media]) || !$this->css[$media]) {
706 return $selector;
707 }
708 // if last is the same, keep it
709 \end($this->css[$media]);
710 $sel = \key($this->css[$media]);
711 if ($sel == $selector) {
712 return $selector;
713 }
714 }
715 while (isset($this->css[$media][$selector])) {
716 $selector .= ' ';
717 }
718 return $selector;
719 }
720 public function css_new_property($media, $selector, $property)
721 {
722 if ($this->get_cfg('preserve_css')) {
723 return $property;
724 }
725 if (!$this->css || !isset($this->css[$media][$selector]) || !$this->css[$media][$selector]) {
726 return $property;
727 }
728 while (isset($this->css[$media][$selector][$property])) {
729 $property .= ' ';
730 }
731 return $property;
732 }
733 public function merge_css_blocks($media, $selector, $css_add)
734 {
735 foreach ($css_add as $property => $value) {
736 $this->css_add_property($media, $selector, $property, $value, \false);
737 }
738 }
739 public function is_important(&$value)
740 {
741 return \strpos($value, '!') !== \false and !\strcasecmp(\substr(\str_replace($this->data['csstidy']['whitespace'], '', $value), -10, 10), '!important');
742 }
743 public function gvw_important($value)
744 {
745 if ($this->is_important($value)) {
746 $value = \trim($value);
747 $value = \substr($value, 0, -9);
748 $value = \trim($value);
749 $value = \substr($value, 0, -1);
750 $value = \trim($value);
751 return $value;
752 }
753 return $value;
754 }
755 public function property_is_next($istring, $pos)
756 {
757 $all_properties =& $this->data['csstidy']['all_properties'];
758 $istring = \substr($istring, $pos, \strlen($istring) - $pos);
759 $pos = \strpos($istring, ':');
760 if ($pos === \false) {
761 return \false;
762 }
763 $istring = \strtolower(\trim(\substr($istring, 0, $pos)));
764 if (isset($all_properties[$istring])) {
765 $this->log('Added semicolon to the end of declaration', 'Warning');
766 return \true;
767 }
768 return \false;
769 }
770 public function property_is_valid($property)
771 {
772 if (\strpos($property, '--') === 0) {
773 $property = "--custom";
774 } elseif (\in_array(\trim($property), $this->data['csstidy']['multiple_properties'])) {
775 $property = \trim($property);
776 }
777 $all_properties =& $this->data['csstidy']['all_properties'];
778 return isset($all_properties[$property]) && \strpos($all_properties[$property], \strtoupper($this->get_cfg('css_level'))) !== \false;
779 }
780 public function parse_string_list($value)
781 {
782 $value = \trim($value);
783 // Case: empty
784 if (!$value) {
785 return array();
786 }
787 $strings = array();
788 $in_str = \false;
789 $current_string = '';
790 for ($i = 0, $_len = \strlen($value); $i < $_len; $i++) {
791 if (($value[$i] === ',' || $value[$i] === ' ') && $in_str === \true) {
792 $in_str = \false;
793 $strings[] = $current_string;
794 $current_string = '';
795 } elseif ($value[$i] === '"' || $value[$i] === "'") {
796 if ($in_str === $value[$i]) {
797 $strings[] = $current_string;
798 $in_str = \false;
799 $current_string = '';
800 continue;
801 } elseif (!$in_str) {
802 $in_str = $value[$i];
803 }
804 } else {
805 if ($in_str) {
806 $current_string .= $value[$i];
807 } else {
808 if (!\preg_match("/[\\s,]/", $value[$i])) {
809 $in_str = \true;
810 $current_string = $value[$i];
811 }
812 }
813 }
814 }
815 if ($current_string) {
816 $strings[] = $current_string;
817 }
818 return $strings;
819 }
820 }
821