protected function getCSSRules($fileName, $fileContent)
 {
     // Remove comments
     $fileContent = preg_replace('#/\\*(?:.(?!/)|[^\\*](?=/)|(?<!\\*)/)*\\*/#s', '', $fileContent);
     #$fileContent = str_replace(array("\t", "\n"), ' ', $fileContent);
     $fileContent = preg_replace('!\\s+!', ' ', $fileContent) . ' ';
     $content = explode('} ', $fileContent);
     if (trim(array_pop($content)) !== '') {
         $this->output->addMessage(Output::FATAL, 'Stylesheet file structure is invalid (Output after last rule)', $fileName);
     }
     $cssRules = array();
     foreach ($content as $section) {
         if (strpos($section, '{') === false) {
             $this->output->addMessage(Output::FATAL, 'Stylesheet file structure is invalid: ' . trim($section), $fileName);
             continue;
         }
         list($rule, $ruleContent) = explode(' {', $section, 2);
         $rule = trim($rule);
         $ruleContent = trim($ruleContent);
         if (strpos($ruleContent, '{') !== false) {
             $this->output->addMessage(Output::FATAL, 'CSS rule is invalid: ' . $rule, $fileName);
             continue;
         }
         if (!isset($cssRules[$rule])) {
             $cssRules[$rule] = '';
         }
         $cssRules[$rule] .= $ruleContent;
     }
     return $cssRules;
 }
 /**
  * Try to find the plural rule for the language
  * @return int
  */
 protected function guessPluralRule()
 {
     if (file_exists($this->originPath . '/' . $this->originLanguagePath . 'common.php')) {
         include $this->originPath . '/' . $this->originLanguagePath . 'common.php';
         if (!isset($lang['PLURAL_RULE'])) {
             $this->output->writelnIfDebug("<info>No plural rule set, falling back to plural rule #1</info>");
         }
     } else {
         $this->output->writelnIfDebug("<info>Could not find common.php, falling back to plural rule #1</info>");
     }
     return isset($lang['PLURAL_RULE']) ? $lang['PLURAL_RULE'] : 1;
 }
 /**
  * Validates the html usage in a string
  *
  * Checks whether the used HTML tags are also used in the original language.
  * Omitting tags is okay, as long as both (start and end) are omitted.
  *
  * @param	string	$file			File to validate
  * @param	string	$key			Key to validate
  * @param	string	$sourceString	Language string to validate against
  * @param	string	$originString	Language string to validate
  * @return	null
  */
 public function validateHtml($file, $key, $sourceString, $originString)
 {
     if ($this->originLanguagePath . 'install.php' === $file && in_array($key, array('INSTALL_CONGRATS_EXPLAIN', 'INSTALL_INTRO_BODY', 'SUPPORT_BODY', 'UPDATE_INSTALLATION_EXPLAIN', 'OVERVIEW_BODY')) || $this->originLanguagePath . 'ucp.php' === $file && in_array($key, array('TERMS_OF_USE_CONTENT', 'PRIVACY_POLICY'))) {
         $sourceString = '<p>' . $sourceString . '</p>';
         $originString = '<p>' . $originString . '</p>';
     }
     $sourceHtml = $originHtml = $openTags = array();
     preg_match_all('/\\<.+?\\>/', $sourceString, $sourceHtml);
     preg_match_all('/\\<.+?\\>/', $originString, $originHtml);
     if (empty($originHtml) || empty($originHtml[0])) {
         // Return when we have no HTML
         return;
     }
     $sourceHtml = isset($sourceHtml[0]) ? $sourceHtml[0] : array();
     $failedUnclosed = false;
     foreach ($originHtml[0] as $possibleHtml) {
         $openingTag = $possibleHtml[1] !== '/';
         $ignoreAdditional = false;
         // The closing tag contains a space
         if (!$openingTag && strpos($possibleHtml, ' ') !== false) {
             $this->output->addMessage(Output::FATAL, 'String is using invalid html: ' . $possibleHtml, $file, $key);
             $ignoreAdditional = true;
         }
         $tag = strpos($possibleHtml, ' ') !== false ? substr($possibleHtml, 1, strpos($possibleHtml, ' ') - 1) : substr($possibleHtml, 1, strpos($possibleHtml, '>') - 1);
         $tag = $openingTag ? $tag : substr($tag, 1);
         if ($openingTag) {
             if (in_array($tag, $openTags)) {
                 if (!$failedUnclosed) {
                     $this->output->addMessage(Output::FATAL, 'String is missing closing tag for html: ' . $tag, $file, $key);
                 }
                 $failedUnclosed = true;
             } else {
                 if (substr($possibleHtml, -3) !== ' />') {
                     $openTags[] = $tag;
                 }
             }
         } else {
             if (empty($openTags)) {
                 if (!$failedUnclosed) {
                     $this->output->addMessage(Output::FATAL, sprintf('String is closing tag for html “%s” which was not opened before', $tag), $file, $key);
                 }
                 $failedUnclosed = true;
             } else {
                 if (end($openTags) != $tag) {
                     if (!$failedUnclosed) {
                         $this->output->addMessage(Output::FATAL, 'String is missing closing tag for html: ' . end($openTags), $file, $key);
                     }
                     $failedUnclosed = true;
                 } else {
                     array_pop($openTags);
                 }
             }
         }
         // HTML tag is not used in original language
         if (!$ignoreAdditional && !in_array($possibleHtml, $sourceHtml) && !isset($this->additionalHtmlFound[$file][$key][$possibleHtml])) {
             $this->additionalHtmlFound[$file][$key][$possibleHtml] = true;
             if (strpos($possibleHtml, '</') === 0) {
                 // Do not add an additional entry for closing tags
                 continue;
             }
             $level = $this->getErrorLevelForAdditionalHtml($possibleHtml);
             if (strpos($possibleHtml, '<a ') === 0) {
                 if (in_array(str_replace('http://', 'https://', $possibleHtml), $sourceHtml)) {
                     $level = Output::NOTICE;
                 } else {
                     if (in_array('</a>', $sourceHtml) || $this->originLanguagePath . 'common.php' === $file && $key === 'TRANSLATION_INFO' || $this->originLanguagePath . 'help_faq.php' === $file || $this->originLanguagePath . 'help_bbcode.php' === $file) {
                         // Source contains a link aswell, mostly IST changed the link to better match the language
                         // It's the translation info with the credit links of the translators
                         // Or the help pages (faq and bbcode help), where links are not as bad as in other places.
                         $level = Output::WARNING;
                     }
                 }
             }
             $this->output->addMessage($level, 'String is using additional html: ' . $possibleHtml, $file, $key);
         }
     }
     if (!empty($openTags) && !$failedUnclosed) {
         $this->output->addMessage(Output::FATAL, 'String is missing closing tag for html: ' . $openTags[0], $file, $key);
     }
 }
 /**
  * Validates the directories
  *
  * Directories should not miss any files.
  * Directories must not contain additional php files.
  * Directories should not contain additional files.
  *
  * @return	array	List of files we can continue to validate.
  */
 public function validate()
 {
     $sourceFiles = $this->getFileList($this->sourcePath);
     // License file is required but missing from en/, so we add it here
     $sourceFiles[] = $this->sourceLanguagePath . 'LICENSE';
     $sourceFiles = array_unique($sourceFiles);
     $originFiles = $this->getFileList($this->originPath);
     $missingSubsilver2Files = $availableSubsilver2Files = array();
     $validFiles = array();
     foreach ($sourceFiles as $sourceFile) {
         $testOriginFile = str_replace('/' . $this->sourceIso . '/', '/' . $this->originIso . '/', $sourceFile);
         if (!in_array($testOriginFile, $originFiles)) {
             if ($this->phpbbVersion === '3.1' && strpos($testOriginFile, 'styles/subsilver2/') === 0) {
                 $missingSubsilver2Files[] = $testOriginFile;
             } else {
                 $this->output->addMessage(Output::FATAL, 'Missing required file', $testOriginFile);
             }
         } else {
             if (substr($sourceFile, -4) != '.gif' && substr($sourceFile, -12) != 'imageset.cfg') {
                 if ($this->phpbbVersion === '3.1' && strpos($testOriginFile, 'styles/subsilver2/') === 0) {
                     $availableSubsilver2Files[] = $testOriginFile;
                 }
                 $validFiles[$sourceFile] = $testOriginFile;
             }
         }
     }
     if ($this->phpbbVersion === '3.1' && !empty($availableSubsilver2Files) && !empty($missingSubsilver2Files)) {
         // Either subsilver2 has to be completly there, or not at all
         foreach ($missingSubsilver2Files as $testOriginFile) {
             $this->output->addMessage(Output::FATAL, 'Missing required file', $testOriginFile);
         }
     } else {
         if ($this->phpbbVersion === '3.1' && empty($availableSubsilver2Files) && !empty($missingSubsilver2Files)) {
             // If subsilver2 is not there at all, we throw a little warning
             $this->output->addMessage(Output::WARNING, 'Missing subsilver2 files');
         }
     }
     foreach ($originFiles as $origin_file) {
         $testSourceFile = str_replace('/' . $this->originIso . '/', '/' . $this->sourceIso . '/', $origin_file);
         if (!in_array($testSourceFile, $sourceFiles)) {
             if (in_array($origin_file, array($this->originLanguagePath . 'AUTHORS', $this->originLanguagePath . 'CHANGELOG', $this->originLanguagePath . 'README', $this->originLanguagePath . 'VERSION'))) {
                 $this->output->addMessage(Output::NOTICE, 'Found additional file', $origin_file);
             } else {
                 if ($this->phpbbVersion == '3.1' && in_array($origin_file, array($this->originLanguagePath . 'AUTHORS.md', $this->originLanguagePath . 'CHANGELOG.md', $this->originLanguagePath . 'README.md', $this->originLanguagePath . 'VERSION.md'))) {
                     $this->output->addMessage(Output::NOTICE, 'Found additional file', $origin_file);
                 } else {
                     if (substr($origin_file, -10) === '/index.htm' || $origin_file === 'index.htm') {
                         $level = Output::NOTICE;
                     } else {
                         if ($this->phpbbVersion === '3.2' && strpos($origin_file, 'styles/subsilver2/') === 0) {
                             $level = Output::FATAL;
                         } else {
                             $level = substr($origin_file, -3) !== '.md' ? Output::FATAL : Output::ERROR;
                         }
                     }
                     $this->output->addMessage($level, 'Found additional file', $origin_file);
                 }
             }
         }
     }
     return $validFiles;
 }