/**
  * Unpackage a module from an xml string
  * does not touch the database
  *
  * @param string $xml The xml data for the package
  * @param boolean $overwrite Should we overwrite files if they exist?
  * @param boolean $brief If set to true, less checking is done and no errors are returned
  * @return array A hash of details about the installed module
  */
 function ExpandXMLPackage($xml, $overwrite = 0, $brief = 0)
 {
     global $gCms;
     // first make sure that we can actually write to the module directory
     $dir = dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . "modules";
     if (!is_writable($dir) && $brief == 0) {
         // directory not writable
         ModuleOperations::SetError(lang('errordirectorynotwritable'));
         return false;
     }
     // start parsing xml
     $parser = xml_parser_create();
     $ret = xml_parse_into_struct($parser, $xml, $val, $xt);
     xml_parser_free($parser);
     if ($ret == 0) {
         ModuleOperations::SetError(lang('errorcouldnotparsexml'));
         return false;
     }
     ModuleOperations::SetError("");
     $havedtdversion = false;
     $moduledetails = array();
     $moduledetails['size'] = strlen($xml);
     $required = array();
     foreach ($val as $elem) {
         $value = isset($elem['value']) ? $elem['value'] : '';
         $type = isset($elem['type']) ? $elem['type'] : '';
         switch ($elem['tag']) {
             case 'NAME':
                 if ($type != 'complete' && $type != 'close') {
                     continue;
                 }
                 // check if this module is already installed
                 if (isset($gCms->modules[$value]) && $overwrite == 0 && $brief == 0) {
                     ModuleOperations::SetError(lang('moduleinstalled'));
                     return false;
                 }
                 $moduledetails['name'] = $value;
                 break;
             case 'DTDVERSION':
                 if ($type != 'complete' && $type != 'close') {
                     continue;
                 }
                 if ($value != MODULE_DTD_VERSION) {
                     ModuleOperations::SetError(lang('errordtdmismatch'));
                     return false;
                 }
                 $havedtdversion = true;
                 break;
             case 'VERSION':
                 if ($type != 'complete' && $type != 'close') {
                     continue;
                 }
                 $moduledetails['version'] = $value;
                 if (isset($gCms->modules[$moduledetails['name']])) {
                     $version = $gCms->modules[$moduledetails['name']]['object']->GetVersion();
                     if (version_compare($moduledetails['version'], $version) < 0 && $brief == 0) {
                         ModuleOperations::SetError(lang('errorattempteddowngrade'));
                         return false;
                     } else {
                         if (version_compare($moduledetails['version'], $version) == 0 && $brief == 0) {
                             ModuleOperations::SetError(lang('moduleinstalled'));
                             return false;
                         }
                     }
                 }
                 break;
             case 'MINCMSVERSION':
                 if ($type != 'complete' && $type != 'close') {
                     continue;
                 }
                 $moduledetails['mincmsversion'] = $value;
                 break;
             case 'MAXCMSVERSION':
                 if ($type != 'complete' && $type != 'close') {
                     continue;
                 }
                 $moduledetails['maxcmsversion'] = $value;
                 break;
             case 'DESCRIPTION':
                 if ($type != 'complete' && $type != 'close') {
                     continue;
                 }
                 $moduledetails['description'] = $value;
                 break;
             case 'HELP':
                 if ($type != 'complete' && $type != 'close') {
                     continue;
                 }
                 $moduledetails['help'] = base64_decode($value);
                 break;
             case 'ABOUT':
                 if ($type != 'complete' && $type != 'close') {
                     continue;
                 }
                 $moduledetails['about'] = base64_decode($value);
                 break;
             case 'REQUIRES':
                 if ($type != 'complete' && $type != 'close') {
                     continue;
                 }
                 if (count($requires) != 2) {
                     continue;
                 }
                 if (!isset($moduledetails['requires'])) {
                     $moduledetails['requires'] = array();
                 }
                 $moduledetails['requires'][] = $requires;
                 $requires = array();
             case 'REQUIREDNAME':
                 $requires['name'] = $value;
                 break;
             case 'REQUIREDVERSION':
                 $requires['version'] = $value;
                 break;
             case 'FILE':
                 if ($type != 'complete' && $type != 'close') {
                     continue;
                 }
                 if ($brief != 0) {
                     continue;
                 }
                 // finished a first file
                 if (!isset($moduledetails['name']) || !isset($moduledetails['version']) || !isset($moduledetails['filename']) || !isset($moduledetails['isdir'])) {
                     print_r($moduledetails);
                     ModuleOperations::SetError(lang('errorincompletexml'));
                     return false;
                 }
                 // ready to go
                 $moduledir = $dir . DIRECTORY_SEPARATOR . $moduledetails['name'];
                 $filename = $moduledir . $moduledetails['filename'];
                 if (!file_exists($moduledir)) {
                     if (!@mkdir($moduledir) && !is_dir($moduledir)) {
                         ModuleOperations::SetError(lang('errorcantcreatefile') . ' ' . $moduledir);
                         break;
                     }
                 } else {
                     if ($moduledetails['isdir']) {
                         if (!@mkdir($filename) && !is_dir($filename)) {
                             ModuleOperations::SetError(lang('errorcantcreatefile') . ' ' . $filename);
                             break;
                         }
                     } else {
                         $data = $moduledetails['filedata'];
                         if (strlen($data)) {
                             $data = base64_decode($data);
                         }
                         $fp = @fopen($filename, "w");
                         if (!$fp) {
                             ModuleOperations::SetError(lang('errorcantcreatefile') . ' ' . $filename);
                         }
                         if (strlen($data)) {
                             @fwrite($fp, $data);
                         }
                         @fclose($fp);
                     }
                 }
                 unset($moduledetails['filedata']);
                 unset($moduledetails['filename']);
                 unset($moduledetails['isdir']);
             case 'FILENAME':
                 $moduledetails['filename'] = $value;
                 break;
             case 'ISDIR':
                 $moduledetails['isdir'] = $value;
                 break;
             case 'DATA':
                 if ($type != 'complete' && $type != 'close') {
                     continue;
                 }
                 $moduledetails['filedata'] = $value;
                 break;
         }
     }
     // foreach
     if ($havedtdversion == false) {
         ModuleOperations::SetError(lang('errordtdmismatch'));
     }
     // we've created the module's directory
     unset($moduledetails['filedata']);
     unset($moduledetails['filename']);
     unset($moduledetails['isdir']);
     if (ModuleOperations::GetLastError() != "") {
         return false;
     }
     return $moduledetails;
 }