compressedData[]=$feedArrayRow;$newOffset=strlen(implode("",$this->compressedData));$addCentralRecord="\x50\x4b\x01\x02";$addCentralRecord.="\x00\x00";$addCentralRecord.="\x0a\x00";$addCentralRecord.="\x00\x00";$addCentralRecord.="\x00\x00";$addCentralRecord.="\x00\x00\x00\x00";$addCentralRecord.=pack("V",0);$addCentralRecord.=pack("V",0);$addCentralRecord.=pack("V",0);$addCentralRecord.=pack("v",strlen($directoryName));$addCentralRecord.=pack("v",0);$addCentralRecord.=pack("v",0);$addCentralRecord.=pack("v",0);$addCentralRecord.=pack("v",0);$ext="\x00\x00\x10\x00";$ext="\xff\xff\xff\xff";$addCentralRecord.=pack("V",16);$addCentralRecord.=pack("V",$this->oldOffset);$this->oldOffset=$newOffset;$addCentralRecord.=$directoryName;$this->centralDirectory[]=$addCentralRecord;} function addFile($data,$directoryName){$directoryName=str_replace("\\","/",$directoryName);$feedArrayRow="\x50\x4b\x03\x04";$feedArrayRow.="\x14\x00";$feedArrayRow.="\x00\x00";$feedArrayRow.="\x08\x00";$feedArrayRow.="\x00\x00\x00\x00";$uncompressedLength=strlen($data);$compression=crc32($data);$gzCompressedData=gzcompress($data);$gzCompressedData=substr(substr($gzCompressedData,0,strlen($gzCompressedData)-4),2);$compressedLength=strlen($gzCompressedData);$feedArrayRow.=pack("V",$compression);$feedArrayRow.=pack("V",$compressedLength);$feedArrayRow.=pack("V",$uncompressedLength);$feedArrayRow.=pack("v",strlen($directoryName));$feedArrayRow.=pack("v",0);$feedArrayRow.=$directoryName;$feedArrayRow.=$gzCompressedData;$feedArrayRow.=pack("V",$compression);$feedArrayRow.=pack("V",$compressedLength);$feedArrayRow.=pack("V",$uncompressedLength);$this->compressedData[]=$feedArrayRow;$newOffset=strlen(implode("",$this->compressedData));$addCentralRecord="\x50\x4b\x01\x02";$addCentralRecord.="\x00\x00";$addCentralRecord.="\x14\x00";$addCentralRecord.="\x00\x00";$addCentralRecord.="\x08\x00";$addCentralRecord.="\x00\x00\x00\x00";$addCentralRecord.=pack("V",$compression);$addCentralRecord.=pack("V",$compressedLength);$addCentralRecord.=pack("V",$uncompressedLength);$addCentralRecord.=pack("v",strlen($directoryName));$addCentralRecord.=pack("v",0);$addCentralRecord.=pack("v",0);$addCentralRecord.=pack("v",0);$addCentralRecord.=pack("v",0);$addCentralRecord.=pack("V",32);$addCentralRecord.=pack("V",$this->oldOffset);$this->oldOffset=$newOffset;$addCentralRecord.=$directoryName;$this->centralDirectory[]=$addCentralRecord;} function getZippedfile(){$data=implode("",$this->compressedData);$controlDirectory=implode("",$this->centralDirectory);return$data.$controlDirectory.$this->endOfCentralDirectory.pack("v",sizeof($this->centralDirectory)).pack("v",sizeof($this->centralDirectory)).pack("V",strlen($controlDirectory)).pack("V",strlen($data))."\x00\x00";} function forceDownload($archiveName){$headerInfo='';if(ini_get('zlib.output_compression')){ini_set('zlib.output_compression','Off');}$data=$this->getZippedFile();header("Pragma:public");header("Expires:0");header("Cache-Control:must-revalidate,post-check=0,pre-check=0");header("Cache-Control:private",false);header("Content-Type:application/zip");header("Content-Disposition:attachment;filename={$archiveName}.xpi;");header("Content-Transfer-Encoding:binary");header("Content-Length:".strlen($data));print("$data");exit;} } // from http://jasonfarrell.com/misc/guid.php // Generates a random GUID per http://www.ietf.org/rfc/rfc4122.txt // e.g. output: 372472a2-d557-4630-bc7d-bae54c934da1 // word*2-, word-, (w)ord-, (w)ord-, word*3 function genGUID(){$guidstr="";for($i=1;$i<=16;$i++){$b=(int)rand(0,0xff);if($i==7){$b&=0x0f;$b|=0x40;}if($i==9){$b&=0x3f;$b|=0x80;}$guidstr.=sprintf("%02s",base_convert($b,10,16));if($i==4||$i==6||$i==8||$i==10){$guidstr.='-';}}return$guidstr;} function insertValues(&$str, $data) { foreach ($data as $k=>$v) { $str=str_replace( '$'.$k, $v, $str ); } return $str; } function convertToRegExp($str) { $str=preg_replace('/([][\\/.?^$+{\|)(])/', '\\\\\1', $str); $str=str_replace('*', '.*', $str); return $str; } if (!empty($_POST)) { error_reporting(E_ALL); //undo magic quotes if necessary if (get_magic_quotes_gpc()) { $_POST=array_map('stripslashes', $_POST); } //build data .. start from post $data=array( 'guid' => genGUID(), 'shortname' => uniqid('script'), 'name' => 'Greased Fennec Compiled User Script', 'description' => '', 'creator' => 'Anonymous', 'homepage' => '', 'version' => '0.1', 'include' => array(), 'exclude' => array(), 'minVersion' => '1.0b2', 'maxVersion' => '1.0.*' ); foreach (array( 'guid', 'creator', 'homepage', 'version', 'minVersion', 'maxVersion' ) as $k) { if (!empty($_POST[$k])) $data[$k]=$_POST[$k]; } //continue build data .. grok values from script $m=array(); $start=strpos($_POST['script'], '==UserScript=='); $end=strpos($_POST['script'], '==/UserScript=='); if ($start>0 && $end>$start) { $scriptData=substr($_POST['script'], $start+15, $end-$start-15); $scriptData=preg_split('/[\n\r]+/', $scriptData); foreach ($scriptData as $line) { $m=array(); if (preg_match('/@name\b(.*)/', $line, $m)) { $data['name']=trim($m[1]); } if (preg_match('/@version\b(.*)/', $line, $m)) { $data['version']=trim($m[1]); } if (preg_match('/@description\b(.*)/', $line, $m)) { $data['description']=trim($m[1]); } if (preg_match('/@include\b(.*)/', $line, $m)) { $data['include'][]=trim($m[1]); } if (preg_match('/@exclude\b(.*)/', $line, $m)) { $data['exclude'][]=trim($m[1]); } } } //make short name from name $data['shortname']=strtolower(substr( preg_replace('/[^a-zA-Z]/', '', $data['name']), 0, 32 )); //convert includes/excludes $data['include']=array_map('convertToRegExp', $data['include']); $data['exclude']=array_map('convertToRegExp', $data['exclude']); //js-ify includes/excludes if (empty($data['include'])) { $data['include']='true'; } else { $data['include']='( /'.implode('/.test(href) || /', $data['include']).'/.test(href) )'; } if (empty($data['exclude'])) { $data['exclude']='true'; } else { $data['exclude']='!( /'.implode('/.test(href) || /', $data['exclude']).'/.test(href) )'; } $xmlProlog=''; //stuff the files that will go in the xpi into an array $xpi=array(); $xpi['chrome.manifest']=<<{\$guid}\$shortname\$version\$description\$creatorGreasemonkey Compiler by Anthony Lieuallen;http://arantius.com/Fennec hack by rich! - http://blog.etiviti.com\$homepage{a23983c0-fd0e-11dc-95ff-0800200c9a66}\$minVersion\$maxVersion EOF; $xpi['chrome/content/script-compiler-overlay.xul']=<< EOF; $xpi['chrome/content/script-compiler.js']=<<addDirectory('chrome/'); foreach ($xpi as $k=>$v) { $zip->addFile($v, $k); } $zip->forceDownload($data['shortname']); print_r($_FILES['script']); } else { ?> User Script Compiler

You may use this tool to create a Firefox Mobile (Fennec) extension (.xpi) from a greasemonkey script.

Type in the appropriate details below, you may leave the default random GUID if you do not have one, or replace it with your own value, which you should definitely do for upgrades to an existing extension.

When pasting in the script, include the ==UserScript== block, as the compiler reads data from there (name, description, includes/excludes).

GUID:
Creator name:
Extension home page:
Extension version:
Firefox min version:
Firefox max version:
User script:

View Source Code

 

This script is a simple hack from the Greasemonkey Script Compiler by: Arantius

If you encounter an issue with this version, please let me know. - only tested on windows and linux version of Firefox Mobile (Fennec)