/**
  * Builds a WCFSetup.
  * 
  * @param	array	$packages
  * @param	string	$outputDirectory
  */
 public function createWcfSetup(array $packages, $outputDirectory = '')
 {
     // ensure output directory is set and exists
     if (empty($outputDirectory)) {
         $outputDirectory = $this->source->buildDirectory;
     } else {
         if (!is_dir($outputDirectory)) {
             FileUtil::makePath($outputDirectory);
         }
     }
     $outputDirectory = FileUtil::addTrailingSlash($outputDirectory);
     // create temporarily directory
     $hash = StringUtil::getRandomID();
     $buildDirectory = $outputDirectory . $hash . '/';
     // populate install directory
     $this->cloneDirectory($buildDirectory, 'install/files');
     $this->cloneDirectory($buildDirectory, 'install/lang');
     $this->cloneDirectory($buildDirectory, 'install/packages');
     // populate setup directory
     $this->cloneDirectory($buildDirectory, 'setup/db');
     $this->cloneDirectory($buildDirectory, 'setup/lang');
     $this->cloneDirectory($buildDirectory, 'setup/license');
     $this->cloneDirectory($buildDirectory, 'setup/template');
     // copy packages
     foreach ($packages as $package) {
         if (!file_exists($package)) {
             throw new SystemException("Required package '" . $package . "' not found.");
         }
         copy($package, $buildDirectory . 'install/packages/' . basename($package));
     }
     // create wcf setup
     $wcfSetup = new TarWriter($outputDirectory . 'WCFSetup.tar.gz', true);
     $wcfSetup->add(array($buildDirectory . 'install', $buildDirectory . 'setup'), '', $buildDirectory);
     $wcfSetup->create();
     // remove temoprarily directory
     $this->deleteDirectory($buildDirectory);
     @rmdir($buildDirectory);
     // set path
     $path = $outputDirectory . 'WCFSetup.tar.gz';
     require_once PB_DIR . 'lib/data/source/file/SourceFileEditor.class.php';
     $sourceFile = SourceFileEditor::create($this->source->sourceID, $path, 'wcfsetup', $this->profileName);
     $this->path = $sourceFile->getPath();
 }
 /**
  * Exports this style.
  * 
  * @param	boolean 	$templates
  * @param	boolean		$images
  * @param	boolean		$icons
  */
 public function export($templates = false, $images = false, $icons = false)
 {
     // create style tar
     require_once WCF_DIR . 'lib/system/io/TarWriter.class.php';
     $styleTarName = FileUtil::getTemporaryFilename('style_', '.tgz');
     $styleTar = new TarWriter($styleTarName, true);
     // append style preview image
     if ($this->image && @file_exists(WCF_DIR . $this->image)) {
         $styleTar->add(WCF_DIR . $this->image, '', FileUtil::addTrailingSlash(dirname(WCF_DIR . $this->image)));
     }
     // create style info file
     $string = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE style SYSTEM \"http://www.woltlab.com/DTDs/SXF/style.dtd\">\n<style>\n";
     // general block
     $string .= "\t<general>\n";
     $string .= "\t\t<stylename><![CDATA[" . StringUtil::escapeCDATA(CHARSET != 'UTF-8' ? StringUtil::convertEncoding(CHARSET, 'UTF-8', $this->styleName) : $this->styleName) . "]]></stylename>\n";
     // style name
     if ($this->styleDescription) {
         $string .= "\t\t<description><![CDATA[" . StringUtil::escapeCDATA(CHARSET != 'UTF-8' ? StringUtil::convertEncoding(CHARSET, 'UTF-8', $this->styleDescription) : $this->styleDescription) . "]]></description>\n";
     }
     // style description
     if ($this->styleVersion) {
         $string .= "\t\t<version><![CDATA[" . StringUtil::escapeCDATA(CHARSET != 'UTF-8' ? StringUtil::convertEncoding(CHARSET, 'UTF-8', $this->styleVersion) : $this->styleVersion) . "]]></version>\n";
     }
     // style version
     if ($this->styleDate) {
         $string .= "\t\t<date><![CDATA[" . StringUtil::escapeCDATA(CHARSET != 'UTF-8' ? StringUtil::convertEncoding(CHARSET, 'UTF-8', $this->styleDate) : $this->styleDate) . "]]></date>\n";
     }
     // style date
     if ($this->image) {
         $string .= "\t\t<image><![CDATA[" . StringUtil::escapeCDATA(CHARSET != 'UTF-8' ? StringUtil::convertEncoding(CHARSET, 'UTF-8', basename($this->image)) : basename($this->image)) . "]]></image>\n";
     }
     // style preview image
     if ($this->copyright) {
         $string .= "\t\t<copyright><![CDATA[" . StringUtil::escapeCDATA(CHARSET != 'UTF-8' ? StringUtil::convertEncoding(CHARSET, 'UTF-8', $this->copyright) : $this->copyright) . "]]></copyright>\n";
     }
     // copyright
     if ($this->license) {
         $string .= "\t\t<license><![CDATA[" . StringUtil::escapeCDATA(CHARSET != 'UTF-8' ? StringUtil::convertEncoding(CHARSET, 'UTF-8', $this->license) : $this->license) . "]]></license>\n";
     }
     // license
     $string .= "\t</general>\n";
     // author block
     $string .= "\t<author>\n";
     if ($this->authorName) {
         $string .= "\t\t<authorname><![CDATA[" . StringUtil::escapeCDATA(CHARSET != 'UTF-8' ? StringUtil::convertEncoding(CHARSET, 'UTF-8', $this->authorName) : $this->authorName) . "]]></authorname>\n";
     }
     // author name
     if ($this->authorURL) {
         $string .= "\t\t<authorurl><![CDATA[" . StringUtil::escapeCDATA(CHARSET != 'UTF-8' ? StringUtil::convertEncoding(CHARSET, 'UTF-8', $this->authorURL) : $this->authorURL) . "]]></authorurl>\n";
     }
     // author URL
     $string .= "\t</author>\n";
     // files block
     $string .= "\t<files>\n";
     $string .= "\t\t<variables>variables.xml</variables>\n";
     // variables
     if ($templates && $this->templatePackID) {
         $string .= "\t\t<templates>templates.tar</templates>\n";
     }
     // templates
     if ($images) {
         $string .= "\t\t<images>images.tar</images>\n";
     }
     // images
     if ($icons) {
         $string .= "\t\t<icons>icons.tar</icons>\n";
     }
     // icons
     $string .= "\t</files>\n";
     $string .= "</style>";
     // append style info file to style tar
     $styleTar->addString(self::INFO_FILE, $string);
     unset($string);
     // create variable list
     $string = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE variables SYSTEM \"http://www.woltlab.com/DTDs/SXF/variables.dtd\">\n<variables>\n";
     // get variables
     $variables = $this->getVariables();
     $exportImages = array();
     foreach ($variables as $name => $value) {
         // search images
         if ($images && $value) {
             if (preg_match_all('~([^/\\s\\$]+\\.(?:gif|jpg|jpeg|png))~i', $value, $matches)) {
                 $exportImages = array_merge($exportImages, $matches[1]);
             }
         }
         $string .= "\t<variable name=\"" . StringUtil::encodeHTML($name) . "\"><![CDATA[" . StringUtil::escapeCDATA(CHARSET != 'UTF-8' ? StringUtil::convertEncoding(CHARSET, 'UTF-8', $value) : $value) . "]]></variable>\n";
     }
     $string .= "</variables>";
     // append variable list to style tar
     $styleTar->addString('variables.xml', $string);
     unset($string);
     if ($templates && $this->templatePackID) {
         require_once WCF_DIR . 'lib/data/template/TemplatePack.class.php';
         $templatePack = new TemplatePack($this->templatePackID);
         // create templates tar
         $templatesTarName = FileUtil::getTemporaryFilename('templates', '.tar');
         $templatesTar = new TarWriter($templatesTarName);
         @chmod($templatesTarName, 0777);
         // append templates to tar
         // get templates
         $sql = "SELECT\t\ttemplate.*, package.package, package.packageDir,\n\t\t\t\t\t\tparent_package.package AS parentPackage, parent_package.packageDir AS parentPackageDir\n\t\t\t\tFROM\t\twcf" . WCF_N . "_template template\n\t\t\t\tLEFT JOIN\twcf" . WCF_N . "_package package\n\t\t\t\tON\t\t(package.packageID = template.packageID)\n\t\t\t\tLEFT JOIN\twcf" . WCF_N . "_package parent_package\n\t\t\t\tON\t\t(parent_package.packageID = package.parentPackageID)\n\t\t\t\tWHERE\t\ttemplate.templatePackID = " . $this->templatePackID;
         $result = WCF::getDB()->sendQuery($sql);
         while ($row = WCF::getDB()->fetchArray($result)) {
             $packageDir = 'com.woltlab.wcf';
             if (!empty($row['parentPackageDir'])) {
                 $packageDir = $row['parentPackage'];
             } else {
                 if (!empty($row['packageDir'])) {
                     $packageDir = $row['package'];
                 }
             }
             $filename = FileUtil::addTrailingSlash(FileUtil::getRealPath(WCF_DIR . $row['packageDir'] . 'templates/' . $templatePack->templatePackFolderName)) . $row['templateName'] . '.tpl';
             $templatesTar->add($filename, $packageDir, dirname($filename));
         }
         // append templates tar to style tar
         $templatesTar->create();
         $styleTar->add($templatesTarName, 'templates.tar', $templatesTarName);
         @unlink($templatesTarName);
     }
     if ($images) {
         // create images tar
         $imagesTarName = FileUtil::getTemporaryFilename('images_', '.tar');
         $imagesTar = new TarWriter($imagesTarName);
         @chmod($imagesTarName, 0777);
         // cache rtl versions
         foreach ($exportImages as $exportImage) {
             if (strpos($exportImage, '-ltr')) {
                 $exportImages[] = str_replace('-ltr', '-rtl', $exportImage);
             }
         }
         // append images to tar
         $path = WCF_DIR . $variables['global.images.location'];
         if (file_exists($path) && is_dir($path)) {
             $handle = opendir($path);
             while (($file = readdir($handle)) !== false) {
                 if (is_file($path . $file) && in_array($file, $exportImages)) {
                     $imagesTar->add($path . $file, '', $path);
                 }
             }
         }
         // append images tar to style tar
         $imagesTar->create();
         $styleTar->add($imagesTarName, 'images.tar', $imagesTarName);
         @unlink($imagesTarName);
     }
     // export icons
     $iconsLocation = FileUtil::addTrailingSlash($variables['global.icons.location']);
     if ($icons && $iconsLocation != 'icon/') {
         // create icons tar
         $iconsTarName = FileUtil::getTemporaryFilename('icons_', '.tar');
         $iconsTar = new TarWriter($iconsTarName);
         @chmod($iconsTar, 0777);
         // get package dirs
         $sql = "SELECT\tpackage, packageDir\n\t\t\t\tFROM\twcf" . WCF_N . "_package\n\t\t\t\tWHERE\tstandalone = 1\n\t\t\t\t\tAND (packageDir <> '' OR package = 'com.woltlab.wcf')";
         $result = WCF::getDB()->sendQuery($sql);
         while ($row = WCF::getDB()->fetchArray($result)) {
             $iconsDir = FileUtil::getRealPath(WCF_DIR . $row['packageDir']) . $iconsLocation;
             $packageIcons = array();
             if (file_exists($iconsDir)) {
                 $icons = glob($iconsDir . '*.png');
                 if (is_array($icons)) {
                     foreach ($icons as $icon) {
                         $packageIcons[] = $icon;
                     }
                 }
             }
             if (count($packageIcons)) {
                 $iconsTar->add($packageIcons, $row['package'] . '/', $iconsDir);
             }
         }
         $iconsTar->create();
         $styleTar->add($iconsTarName, 'icons.tar', $iconsTarName);
         @unlink($iconsTarName);
     }
     // output file content
     $styleTar->create();
     readfile($styleTarName);
     @unlink($styleTarName);
 }
 /**
  * Creates complete archive.
  *
  * @param	string	$directory
  * @param	string	$filename
  */
 public function createArchive($directory, $filename, $removeAfter)
 {
     $buildDirectory = '';
     $directories = array('acptemplates', 'files', 'pip', 'templates');
     $directory = FileUtil::addTrailingSlash($this->source->sourceDirectory . $directory);
     $location = '';
     // skip if no directory was given
     if (!is_dir($directory)) {
         throw new SystemException('Given directory "' . $directory . '" is not valid.');
     }
     $buildDirectory = FileUtil::addTrailingSlash($this->source->buildDirectory);
     $location = $buildDirectory . $filename;
     $package = new TarWriter($location, true);
     // read correct directory for languages
     $languagesInRoot = true;
     $languagesExist = false;
     if (file_exists($directory . self::LANGUAGE_DIR) && is_dir($directory . self::LANGUAGE_DIR)) {
         $languagesExist = true;
         $xml = new XML($directory . 'package.xml');
         $nodes = $xml->getChildren();
         foreach ($nodes as $node) {
             if ($node->getName() != 'instructions') {
                 continue;
             }
             $subNodes = $xml->getChildren($node);
             foreach ($subNodes as $subNode) {
                 if ($subNode->getName() != 'languages') {
                     continue;
                 }
                 if (substr($xml->getCDATA($subNode), 0, strlen(self::LANGUAGE_DIR) + 1) == self::LANGUAGE_DIR . '/') {
                     $languagesInRoot = false;
                 }
             }
         }
     }
     // if files should be in root skip languages directory and copy language files into root
     if ($languagesExist && $languagesInRoot) {
         $this->excludeFiles[] = self::LANGUAGE_DIR;
         $files = DirectoryUtil::getInstance($directory . self::LANGUAGE_DIR . '/', false)->getFilesObj(SORT_DESC);
         foreach ($files as $filename => $obj) {
             if ($filename == '.svn') {
                 continue;
             }
             # $obj->isDir()) continue;
             copy($directory . self::LANGUAGE_DIR . '/' . $filename, $directory . $filename);
             // register them for removing
             PackageHelper::registerTemporaryFile($directory . $filename);
         }
     }
     // try to open directory
     $dir = DirectoryUtil::getInstance($directory, false);
     foreach ($dir->getFiles() as $filename) {
         // skip files
         if (in_array($filename, $this->excludeFiles)) {
             continue;
         }
         if ($this->ignoreDotFiles && substr($filename, 0, 1) == '.' && !in_array($filename, $this->allowedDotFiles)) {
             continue;
         }
         /* easteregg
         				if ($filename == 'package.xml') {
         					copy($directory.$filename, $directory.$filename.'.bak');
         					$new = file_get_contents($directory.$filename);
         					$new = str_replace('</packageinformation>', '<!--meta name="generator" content="PackageBuilder'.(SHOW_VERSION_NUMBER ? ' v'.PACKAGE_VERSION : '').'"--></packageinformation>', $new);
         					file_put_contents($directory.$filename, $new);
         				}
         			*/
         // handle files
         if (!is_dir($directory . $filename)) {
             // add file
             $package->add($directory . $filename, '', $directory);
             /* easteregg
             				if ($filename == 'package.xml') {
             					unlink($directory.$filename);
             					rename($directory.$filename.'.bak', $directory.$filename);
             				}
             			*/
             continue;
         }
         // skip directories
         if (in_array($filename, $directories)) {
             // create tarball from special directories
             $archive = new TarWriter($buildDirectory . $filename . '.tar', false);
             $this->addFilesRecursive($archive, $directory, $filename, $filename . '/');
             $archive->create();
             // add previously created tarball
             $package->add($buildDirectory . $filename . '.tar', '', $buildDirectory);
         } else {
             // add sourceDirectory
             $this->addFilesRecursive($package, $directory, $filename);
         }
     }
     // create complete package
     $package->create();
     // cleanup, remove previous created tarballs
     DirectoryUtil::destroy($this->source->buildDirectory);
     $dir = DirectoryUtil::getInstance($this->source->buildDirectory);
     $dir->removePattern('/.*\\.tar$/');
     if ($removeAfter) {
         PackageHelper::registerTemporaryFile($location);
     }
     return $location;
 }