/**
  * format() in font-face needs quoted values for somes browser (FF at least)
  *
  * @param $value
  * @return string
  */
 function quote_font_format($value)
 {
     if (strncmp($value, 'format', 6) == 0) {
         $p = strrpos($value, ")");
         $end = substr($value, $p);
         $format_strings = csstidy::parse_string_list(substr($value, 7, $p - 7));
         if (!$format_strings) {
             $value = "";
         } else {
             $value = "format(";
             foreach ($format_strings as $format_string) {
                 $value .= '"' . str_replace('"', '\\"', $format_string) . '",';
             }
             $value = substr($value, 0, -1) . $end;
         }
     }
     return $value;
 }
 /**
  * Parses CSS in $string. The code is saved as array in $this->css
  * @param string $string the CSS code
  * @access public
  * @return bool
  * @version 1.1
  */
 function parse($string)
 {
     // Temporarily set locale to en_US in order to handle floats properly
     $old = @setlocale(LC_ALL, 0);
     @setlocale(LC_ALL, 'C');
     // PHP bug? Settings need to be refreshed in PHP4
     $this->print = new csstidy_print($this);
     //$this->optimise = new csstidy_optimise($this);
     $all_properties =& $GLOBALS['csstidy']['all_properties'];
     $at_rules =& $GLOBALS['csstidy']['at_rules'];
     $quoted_string_properties =& $GLOBALS['csstidy']['quoted_string_properties'];
     $this->css = array();
     $this->print->input_css = $string;
     $string = str_replace("\r\n", "\n", $string) . ' ';
     $cur_comment = '';
     for ($i = 0, $size = strlen($string); $i < $size; $i++) {
         if ($string[$i] === "\n" || $string[$i] === "\r") {
             ++$this->line;
         }
         switch ($this->status) {
             /* Case in at-block */
             case 'at':
                 if (csstidy::is_token($string, $i)) {
                     if ($string[$i] === '/' && @$string[$i + 1] === '*') {
                         $this->status = 'ic';
                         ++$i;
                         $this->from[] = 'at';
                     } elseif ($string[$i] === '{') {
                         $this->status = 'is';
                         $this->at = $this->css_new_media_section($this->at);
                         $this->_add_token(AT_START, $this->at);
                     } elseif ($string[$i] === ',') {
                         $this->at = trim($this->at) . ',';
                     } elseif ($string[$i] === '\\') {
                         $this->at .= $this->_unicode($string, $i);
                     } elseif (in_array($string[$i], array('(', ')', ':', '.', '/'))) {
                         $this->at .= $string[$i];
                     }
                 } else {
                     $lastpos = strlen($this->at) - 1;
                     if (!((ctype_space($this->at[$lastpos]) || csstidy::is_token($this->at, $lastpos) && $this->at[$lastpos] === ',') && ctype_space($string[$i]))) {
                         $this->at .= $string[$i];
                     }
                 }
                 break;
                 /* Case in-selector */
             /* Case in-selector */
             case 'is':
                 if (csstidy::is_token($string, $i)) {
                     if ($string[$i] === '/' && @$string[$i + 1] === '*' && trim($this->selector) == '') {
                         $this->status = 'ic';
                         ++$i;
                         $this->from[] = 'is';
                     } elseif ($string[$i] === '@' && trim($this->selector) == '') {
                         // Check for at-rule
                         $this->invalid_at = true;
                         foreach ($at_rules as $name => $type) {
                             if (!strcasecmp(substr($string, $i + 1, strlen($name)), $name)) {
                                 $type === 'at' ? $this->at = '@' . $name : ($this->selector = '@' . $name);
                                 $this->status = $type;
                                 $i += strlen($name);
                                 $this->invalid_at = false;
                             }
                         }
                         if ($this->invalid_at) {
                             $this->selector = '@';
                             $invalid_at_name = '';
                             for ($j = $i + 1; $j < $size; ++$j) {
                                 if (!ctype_alpha($string[$j])) {
                                     break;
                                 }
                                 $invalid_at_name .= $string[$j];
                             }
                             $this->log('Invalid @-rule: ' . $invalid_at_name . ' (removed)', 'Warning');
                         }
                     } elseif ($string[$i] === '"' || $string[$i] === "'") {
                         $this->cur_string[] = $string[$i];
                         $this->status = 'instr';
                         $this->str_char[] = $string[$i];
                         $this->from[] = 'is';
                         /* fixing CSS3 attribute selectors, i.e. a[href$=".mp3" */
                         $this->quoted_string[] = $string[$i - 1] == '=';
                     } elseif ($this->invalid_at && $string[$i] === ';') {
                         $this->invalid_at = false;
                         $this->status = 'is';
                     } elseif ($string[$i] === '{') {
                         $this->status = 'ip';
                         if ($this->at == '') {
                             $this->at = $this->css_new_media_section(DEFAULT_AT);
                         }
                         $this->selector = $this->css_new_selector($this->at, $this->selector);
                         $this->_add_token(SEL_START, $this->selector);
                         $this->added = false;
                     } elseif ($string[$i] === '}') {
                         $this->_add_token(AT_END, $this->at);
                         $this->at = '';
                         $this->selector = '';
                         $this->sel_separate = array();
                     } elseif ($string[$i] === ',') {
                         $this->selector = trim($this->selector) . ',';
                         $this->sel_separate[] = strlen($this->selector);
                     } elseif ($string[$i] === '\\') {
                         $this->selector .= $this->_unicode($string, $i);
                     } elseif ($string[$i] === '*' && @in_array($string[$i + 1], array('.', '#', '[', ':'))) {
                         // remove unnecessary universal selector, FS#147
                     } else {
                         $this->selector .= $string[$i];
                     }
                 } else {
                     $lastpos = strlen($this->selector) - 1;
                     if ($lastpos == -1 || !((ctype_space($this->selector[$lastpos]) || csstidy::is_token($this->selector, $lastpos) && $this->selector[$lastpos] === ',') && ctype_space($string[$i]))) {
                         $this->selector .= $string[$i];
                     } else {
                         if (ctype_space($string[$i]) && $this->get_cfg('preserve_css') && !$this->get_cfg('merge_selectors')) {
                             $this->selector .= $string[$i];
                         }
                     }
                 }
                 break;
                 /* Case in-property */
             /* Case in-property */
             case 'ip':
                 if (csstidy::is_token($string, $i)) {
                     if (($string[$i] === ':' || $string[$i] === '=') && $this->property != '') {
                         $this->status = 'iv';
                         if (!$this->get_cfg('discard_invalid_properties') || csstidy::property_is_valid($this->property)) {
                             $this->property = $this->css_new_property($this->at, $this->selector, $this->property);
                             $this->_add_token(PROPERTY, $this->property);
                         }
                     } elseif ($string[$i] === '/' && @$string[$i + 1] === '*' && $this->property == '') {
                         $this->status = 'ic';
                         ++$i;
                         $this->from[] = 'ip';
                     } elseif ($string[$i] === '}') {
                         $this->explode_selectors();
                         $this->status = 'is';
                         $this->invalid_at = false;
                         $this->_add_token(SEL_END, $this->selector);
                         $this->selector = '';
                         $this->property = '';
                     } elseif ($string[$i] === ';') {
                         $this->property = '';
                     } elseif ($string[$i] === '\\') {
                         $this->property .= $this->_unicode($string, $i);
                     } elseif ($this->property == '' and !ctype_space($string[$i])) {
                         $this->property .= $string[$i];
                     }
                 } elseif (!ctype_space($string[$i])) {
                     $this->property .= $string[$i];
                 }
                 break;
                 /* Case in-value */
             /* Case in-value */
             case 'iv':
                 $pn = ($string[$i] === "\n" || $string[$i] === "\r") && $this->property_is_next($string, $i + 1) || $i == strlen($string) - 1;
                 if ((csstidy::is_token($string, $i) || $pn) && !($string[$i] == ',' && !ctype_space($string[$i + 1]))) {
                     if ($string[$i] === '/' && @$string[$i + 1] === '*') {
                         $this->status = 'ic';
                         ++$i;
                         $this->from[] = 'iv';
                     } elseif ($string[$i] === '"' || $string[$i] === "'" || $string[$i] === '(') {
                         $this->cur_string[] = $string[$i];
                         $this->str_char[] = $string[$i] === '(' ? ')' : $string[$i];
                         $this->status = 'instr';
                         $this->from[] = 'iv';
                         $this->quoted_string[] = in_array(strtolower($this->property), $quoted_string_properties);
                     } elseif ($string[$i] === ',') {
                         $this->sub_value = trim($this->sub_value) . ',';
                     } elseif ($string[$i] === '\\') {
                         $this->sub_value .= $this->_unicode($string, $i);
                     } elseif ($string[$i] === ';' || $pn) {
                         if ($this->selector[0] === '@' && isset($at_rules[substr($this->selector, 1)]) && $at_rules[substr($this->selector, 1)] === 'iv') {
                             $this->status = 'is';
                             switch ($this->selector) {
                                 case '@charset':
                                     /* Add quotes to charset */
                                     $this->sub_value_arr[] = '"' . trim($this->sub_value) . '"';
                                     $this->charset = $this->sub_value_arr[0];
                                     break;
                                 case '@namespace':
                                     /* Add quotes to namespace */
                                     $this->sub_value_arr[] = '"' . trim($this->sub_value) . '"';
                                     $this->namespace = implode(' ', $this->sub_value_arr);
                                     break;
                                 case '@import':
                                     $this->sub_value = trim($this->sub_value);
                                     if (empty($this->sub_value_arr)) {
                                         // Quote URLs in imports only if they're not already inside url() and not already quoted.
                                         if (substr($this->sub_value, 0, 4) != 'url(') {
                                             if (!($this->sub_value[0] == substr($this->sub_value, -1) && in_array($this->sub_value[0], array("'", '"')))) {
                                                 $this->sub_value = '"' . $this->sub_value . '"';
                                             }
                                         }
                                     }
                                     $this->sub_value_arr[] = $this->sub_value;
                                     $this->import[] = implode(' ', $this->sub_value_arr);
                                     break;
                             }
                             $this->sub_value_arr = array();
                             $this->sub_value = '';
                             $this->selector = '';
                             $this->sel_separate = array();
                         } else {
                             $this->status = 'ip';
                         }
                     } elseif ($string[$i] !== '}') {
                         $this->sub_value .= $string[$i];
                     }
                     if (($string[$i] === '}' || $string[$i] === ';' || $pn) && !empty($this->selector)) {
                         if ($this->at == '') {
                             $this->at = $this->css_new_media_section(DEFAULT_AT);
                         }
                         // case settings
                         if ($this->get_cfg('lowercase_s')) {
                             $this->selector = strtolower($this->selector);
                         }
                         $this->property = strtolower($this->property);
                         $this->optimise->subvalue();
                         if ($this->sub_value != '') {
                             if (substr($this->sub_value, 0, 6) == 'format') {
                                 $format_strings = csstidy::parse_string_list(substr($this->sub_value, 7, -1));
                                 if (!$format_strings) {
                                     $this->sub_value = "";
                                 } else {
                                     $this->sub_value = "format(";
                                     foreach ($format_strings as $format_string) {
                                         $this->sub_value .= '"' . str_replace('"', '\\"', $format_string) . '",';
                                     }
                                     $this->sub_value = substr($this->sub_value, 0, -1) . ")";
                                 }
                             }
                             if ($this->sub_value != '') {
                                 $this->sub_value_arr[] = $this->sub_value;
                             }
                             $this->sub_value = '';
                         }
                         $this->value = array_shift($this->sub_value_arr);
                         while (count($this->sub_value_arr)) {
                             //$this->value .= (substr($this->value,-1,1)==','?'':' ').array_shift($this->sub_value_arr);
                             $this->value .= ' ' . array_shift($this->sub_value_arr);
                         }
                         $this->optimise->value();
                         $valid = csstidy::property_is_valid($this->property);
                         if ((!$this->invalid_at || $this->get_cfg('preserve_css')) && (!$this->get_cfg('discard_invalid_properties') || $valid)) {
                             $this->css_add_property($this->at, $this->selector, $this->property, $this->value);
                             $this->_add_token(VALUE, $this->value);
                             $this->optimise->shorthands();
                         }
                         if (!$valid) {
                             if ($this->get_cfg('discard_invalid_properties')) {
                                 $this->log('Removed invalid property: ' . $this->property, 'Warning');
                             } else {
                                 $this->log('Invalid property in ' . strtoupper($this->get_cfg('css_level')) . ': ' . $this->property, 'Warning');
                             }
                         }
                         $this->property = '';
                         $this->sub_value_arr = array();
                         $this->value = '';
                     }
                     if ($string[$i] === '}') {
                         $this->explode_selectors();
                         $this->_add_token(SEL_END, $this->selector);
                         $this->status = 'is';
                         $this->invalid_at = false;
                         $this->selector = '';
                     }
                 } elseif (!$pn) {
                     $this->sub_value .= $string[$i];
                     if (ctype_space($string[$i]) || $string[$i] == ',') {
                         $this->optimise->subvalue();
                         if ($this->sub_value != '') {
                             $this->sub_value_arr[] = $this->sub_value;
                             $this->sub_value = '';
                         }
                     }
                 }
                 break;
                 /* Case in string */
             /* Case in string */
             case 'instr':
                 $_str_char = $this->str_char[count($this->str_char) - 1];
                 $_cur_string = $this->cur_string[count($this->cur_string) - 1];
                 $temp_add = $string[$i];
                 // Add another string to the stack. Strings can't be nested inside of quotes, only parentheses, but
                 // parentheticals can be nested more than once.
                 if ($_str_char === ")" && ($string[$i] === "(" || $string[$i] === '"' || $string[$i] === '\'') && !csstidy::escaped($string, $i)) {
                     $this->cur_string[] = $string[$i];
                     $this->str_char[] = $string[$i] == "(" ? ")" : $string[$i];
                     $this->from[] = 'instr';
                     $this->quoted_string[] = !($string[$i] === "(");
                     continue;
                 }
                 if ($_str_char !== ")" && ($string[$i] === "\n" || $string[$i] === "\r") && !($string[$i - 1] === '\\' && !csstidy::escaped($string, $i - 1))) {
                     $temp_add = "\\A";
                     $this->log('Fixed incorrect newline in string', 'Warning');
                 }
                 $_cur_string .= $temp_add;
                 if ($string[$i] === $_str_char && !csstidy::escaped($string, $i)) {
                     $_quoted_string = array_pop($this->quoted_string);
                     $this->status = array_pop($this->from);
                     if (!preg_match('|[' . implode('', $GLOBALS['csstidy']['whitespace']) . ']|uis', $_cur_string) && $this->property !== 'content') {
                         if (!$_quoted_string) {
                             if ($_str_char !== ')') {
                                 // Convert properties like
                                 // font-family: 'Arial';
                                 // to
                                 // font-family: Arial;
                                 // or
                                 // url("abc")
                                 // to
                                 // url(abc)
                                 $_cur_string = substr($_cur_string, 1, -1);
                             }
                         } else {
                             $_quoted_string = false;
                         }
                     }
                     array_pop($this->cur_string);
                     array_pop($this->str_char);
                     if ($_str_char === ")") {
                         $_cur_string = "(" . trim(substr($_cur_string, 1, -1)) . ")";
                     }
                     if ($this->status === 'iv') {
                         if (!$_quoted_string) {
                             if (strpos($_cur_string, ',') !== false) {
                                 // we can on only remove space next to ','
                                 $_cur_string = implode(',', array_map('trim', explode(',', $_cur_string)));
                             }
                             // and multiple spaces (too expensive)
                             if (strpos($_cur_string, '  ') !== false) {
                                 $_cur_string = preg_replace(",\\s+,", " ", $_cur_string);
                             }
                         }
                         $this->sub_value .= $_cur_string;
                     } elseif ($this->status === 'is') {
                         $this->selector .= $_cur_string;
                     } elseif ($this->status === 'instr') {
                         $this->cur_string[count($this->cur_string) - 1] .= $_cur_string;
                     }
                 } else {
                     $this->cur_string[count($this->cur_string) - 1] = $_cur_string;
                 }
                 break;
                 /* Case in-comment */
             /* Case in-comment */
             case 'ic':
                 if ($string[$i] === '*' && $string[$i + 1] === '/') {
                     $this->status = array_pop($this->from);
                     $i++;
                     $this->_add_token(COMMENT, $cur_comment);
                     $cur_comment = '';
                 } else {
                     $cur_comment .= $string[$i];
                 }
                 break;
         }
     }
     $this->optimise->postparse();
     $this->print->_reset();
     @setlocale(LC_ALL, $old);
     // Set locale back to original setting
     return !(empty($this->css) && empty($this->import) && empty($this->charset) && empty($this->tokens) && empty($this->namespace));
 }