|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /** 00003 * jsmin.php - PHP implementation of Douglas Crockford's JSMin. 00004 * 00005 * This is pretty much a direct port of jsmin.c to PHP with just a few 00006 * PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and 00007 * outputs to stdout, this library accepts a string as input and returns another 00008 * string as output. 00009 * 00010 * PHP 5 or higher is required. 00011 * 00012 * Permission is hereby granted to use this version of the library under the 00013 * same terms as jsmin.c, which has the following license: 00014 * 00015 * -- 00016 * Copyright (c) 2002 Douglas Crockford (www.crockford.com) 00017 * 00018 * Permission is hereby granted, free of charge, to any person obtaining a copy of 00019 * this software and associated documentation files (the "Software"), to deal in 00020 * the Software without restriction, including without limitation the rights to 00021 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 00022 * of the Software, and to permit persons to whom the Software is furnished to do 00023 * so, subject to the following conditions: 00024 * 00025 * The above copyright notice and this permission notice shall be included in all 00026 * copies or substantial portions of the Software. 00027 * 00028 * The Software shall be used for Good, not Evil. 00029 * 00030 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00031 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00032 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00033 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00034 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00035 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00036 * SOFTWARE. 00037 * -- 00038 * 00039 * @package JSMin 00040 * @author Ryan Grove <ryan@wonko.com> 00041 * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c) 00042 * @copyright 2007 Ryan Grove <ryan@wonko.com> (PHP port) 00043 * @license http://opensource.org/licenses/mit-license.php MIT License 00044 * @version 1.1.0 (2007-06-01) 00045 * @link http://code.google.com/p/jsmin-php/ 00046 * 00047 * TYPO3 SVN ID: $Id: jsmin.php 2663 2007-11-05 09:22:23Z ingmars $ 00048 */ 00049 00050 class JSMin { 00051 const ORD_LF = 10; 00052 const ORD_SPACE = 32; 00053 00054 protected $a = ''; 00055 protected $b = ''; 00056 protected $input = ''; 00057 protected $inputIndex = 0; 00058 protected $inputLength = 0; 00059 protected $lookAhead = null; 00060 protected $output = array(); 00061 00062 // -- Public Static Methods -------------------------------------------------- 00063 00064 public static function minify($js) { 00065 $jsmin = new JSMin($js); 00066 return $jsmin->min(); 00067 } 00068 00069 // -- Public Instance Methods ------------------------------------------------ 00070 00071 public function __construct($input) { 00072 $this->input = str_replace("\r\n", "\n", $input); 00073 $this->inputLength = strlen($this->input); 00074 } 00075 00076 // -- Protected Instance Methods --------------------------------------------- 00077 00078 protected function action($d) { 00079 switch($d) { 00080 case 1: 00081 $this->output[] = $this->a; 00082 00083 case 2: 00084 $this->a = $this->b; 00085 00086 if ($this->a === "'" || $this->a === '"') { 00087 for (;;) { 00088 $this->output[] = $this->a; 00089 $this->a = $this->get(); 00090 00091 if ($this->a === $this->b) { 00092 break; 00093 } 00094 00095 if (ord($this->a) <= self::ORD_LF) { 00096 throw new JSMinException('Unterminated string literal.'); 00097 } 00098 00099 if ($this->a === '\\') { 00100 $this->output[] = $this->a; 00101 $this->a = $this->get(); 00102 } 00103 } 00104 } 00105 00106 case 3: 00107 $this->b = $this->next(); 00108 00109 if ($this->b === '/' && ( 00110 $this->a === '(' || $this->a === ',' || $this->a === '=' || 00111 $this->a === ':' || $this->a === '[' || $this->a === '!' || 00112 $this->a === '&' || $this->a === '|' || $this->a === '?')) { 00113 00114 $this->output[] = $this->a; 00115 $this->output[] = $this->b; 00116 00117 for (;;) { 00118 $this->a = $this->get(); 00119 00120 if ($this->a === '/') { 00121 break; 00122 } 00123 elseif ($this->a === '\\') { 00124 $this->output[] = $this->a; 00125 $this->a = $this->get(); 00126 } 00127 elseif (ord($this->a) <= self::ORD_LF) { 00128 throw new JSMinException('Unterminated regular expression '. 00129 'literal.'); 00130 } 00131 00132 $this->output[] = $this->a; 00133 } 00134 00135 $this->b = $this->next(); 00136 } 00137 } 00138 } 00139 00140 protected function get() { 00141 $c = $this->lookAhead; 00142 $this->lookAhead = null; 00143 00144 if ($c === null) { 00145 if ($this->inputIndex < $this->inputLength) { 00146 $c = $this->input[$this->inputIndex]; 00147 $this->inputIndex += 1; 00148 } 00149 else { 00150 $c = null; 00151 } 00152 } 00153 00154 if ($c === "\r") { 00155 return "\n"; 00156 } 00157 00158 if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) { 00159 return $c; 00160 } 00161 00162 return ' '; 00163 } 00164 00165 protected function isAlphaNum($c) { 00166 return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1; 00167 } 00168 00169 protected function min() { 00170 $this->a = "\n"; 00171 $this->action(3); 00172 00173 while ($this->a !== null) { 00174 switch ($this->a) { 00175 case ' ': 00176 if ($this->isAlphaNum($this->b)) { 00177 $this->action(1); 00178 } 00179 else { 00180 $this->action(2); 00181 } 00182 break; 00183 00184 case "\n": 00185 switch ($this->b) { 00186 case '{': 00187 case '[': 00188 case '(': 00189 case '+': 00190 case '-': 00191 $this->action(1); 00192 break; 00193 00194 case ' ': 00195 $this->action(3); 00196 break; 00197 00198 default: 00199 if ($this->isAlphaNum($this->b)) { 00200 $this->action(1); 00201 } 00202 else { 00203 $this->action(2); 00204 } 00205 } 00206 break; 00207 00208 default: 00209 switch ($this->b) { 00210 case ' ': 00211 if ($this->isAlphaNum($this->a)) { 00212 $this->action(1); 00213 break; 00214 } 00215 00216 $this->action(3); 00217 break; 00218 00219 case "\n": 00220 switch ($this->a) { 00221 case '}': 00222 case ']': 00223 case ')': 00224 case '+': 00225 case '-': 00226 case '"': 00227 case "'": 00228 $this->action(1); 00229 break; 00230 00231 default: 00232 if ($this->isAlphaNum($this->a)) { 00233 $this->action(1); 00234 } 00235 else { 00236 $this->action(3); 00237 } 00238 } 00239 break; 00240 00241 default: 00242 $this->action(1); 00243 break; 00244 } 00245 } 00246 } 00247 00248 return implode('', $this->output); 00249 } 00250 00251 protected function next() { 00252 $c = $this->get(); 00253 00254 if ($c === '/') { 00255 switch($this->peek()) { 00256 case '/': 00257 for (;;) { 00258 $c = $this->get(); 00259 00260 if (ord($c) <= self::ORD_LF) { 00261 return $c; 00262 } 00263 } 00264 00265 case '*': 00266 $this->get(); 00267 00268 for (;;) { 00269 switch($this->get()) { 00270 case '*': 00271 if ($this->peek() === '/') { 00272 $this->get(); 00273 return ' '; 00274 } 00275 break; 00276 00277 case null: 00278 throw new JSMinException('Unterminated comment.'); 00279 } 00280 } 00281 00282 default: 00283 return $c; 00284 } 00285 } 00286 00287 return $c; 00288 } 00289 00290 protected function peek() { 00291 $this->lookAhead = $this->get(); 00292 return $this->lookAhead; 00293 } 00294 } 00295 00296 // -- Exceptions --------------------------------------------------------------- 00297 class JSMinException extends Exception {} 00298 ?>
1.8.0