ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
JSMin_lib.php
Go to the documentation of this file.
1<?php
85define('JSMIN_VERSION', '0.2');
86
92define('EOF', FALSE);
93
99define('ORD_NL', ord("\n"));
100define('ORD_space', ord(' '));
101define('ORD_cA', ord('A'));
102define('ORD_cZ', ord('Z'));
103define('ORD_a', ord('a'));
104define('ORD_z', ord('z'));
105define('ORD_0', ord('0'));
106define('ORD_9', ord('9'));
107
111/*
112class JSMinException extends Exception {
113}
114*/
116}
117
123}
124
130}
131
137}
138
144}
145
150define ('JSMIN_ACT_FULL', 1);
151
156define ('JSMIN_ACT_BUF', 2);
157
162define ('JSMIN_ACT_IMM', 3);
163
175class JSMin {
176
182 var $in;
183
189 var $out;
190
195 var $theA;
196
201 var $theB;
202
204 var $inLength = 0;
205 var $inPos = 0;
206 var $isString = false;
207
214 function isAlphaNum($c) {
215
216 // Get ASCII value of character for C-like comparisons
217
218 $a = ord($c);
219
220 // Compare using defined character ordinals, or between PHP strings
221 // Note : === is micro-faster than == when types are known to be the same
222
223 return
224 ($a >= ORD_a && $a <= ORD_z) ||
225 ($a >= ORD_0 && $a <= ORD_9) ||
226 ($a >= ORD_cA && $a <= ORD_cZ) ||
227 $c === '_' || $c === '$' || $c === '\\' || $a > 126
228 ;
229 }
230
240 function get() {
241
242 // Get next input character and advance position in file
243
244 if ($this->isString) {
245 if ($this->inPos < $this->inLength) {
246 $c = $this->in[$this->inPos];
247 ++$this->inPos;
248 }
249 else {
250 return EOF;
251 }
252 }
253 else
254 $c = $this->in->fgetc();
255
256 // Test for non-problematic characters
257
258 if ($c === "\n" || $c === EOF || ord($c) >= ORD_space) {
259 return $c;
260 }
261
262 // else
263 // Make linefeeds into newlines
264
265 if ($c === "\r") {
266 return "\n";
267 }
268
269 // else
270 // Consider space
271
272 return ' ';
273 }
274
283 function peek() {
284
285 if ($this->isString) {
286 if ($this->inPos < $this->inLength) {
287 $c = $this->in[$this->inPos];
288 }
289 else {
290 return EOF;
291 }
292 }
293 else {
294 // Get next input character
295
296 $c = $this->in->fgetc();
297
298 // Regress position in file
299
300 $this->in->fseek(-1, SEEK_CUR);
301
302 // Return character obtained
303 }
304
305 return $c;
306 }
307
312 function put($c)
313 {
314 if ($this->isString) {
315 $this->out .= $c;
316 }
317 else {
318 $this->out->fwrite($c);
319 }
320 }
321
331 function next() {
332
333 // Get next char from input, translated if necessary
334
335 $c = $this->get();
336
337 // Check comment possibility
338
339 if ($c == '/') {
340
341 // Look ahead : a comment is two slashes or slashes followed by asterisk (to be closed)
342
343 switch ($this->peek()) {
344
345 case '/' :
346
347 // Comment is up to the end of the line
348 // TOTEST : simple $this->in->fgets()
349
350 while (true) {
351
352 $c = $this->get();
353
354 if (ord($c) <= ORD_NL) {
355 return $c;
356 }
357 }
358
359 case '*' :
360
361 // Comment is up to comment close.
362 // Might not be terminated, if we hit the end of file.
363
364 while (true) {
365
366 // N.B. not using switch() because of having to test EOF with ===
367
368 $c = $this->get();
369
370 if ($c == '*') {
371
372 // Comment termination if the char ahead is a slash
373
374 if ($this->peek() == '/') {
375
376 // Advance again and make into a single space
377
378 $this->get();
379 return ' ';
380 }
381 }
382 else if ($c === EOF) {
383
384 // Whoopsie
385
386 //throw new UnterminatedCommentJSMinException();
387 trigger_error('UnterminatedComment', E_USER_ERROR);
388 }
389 }
390
391 default :
392
393 // Not a comment after all
394
395 return $c;
396 }
397 }
398
399 // No risk of a comment
400
401 return $c;
402 }
403
418 function action($action) {
419
420 // Choice of possible actions
421 // Note the frequent fallthroughs : the actions are decrementally "long"
422
423 switch ($action) {
424
425 case JSMIN_ACT_FULL :
426
427 // Write A to output, then fall through
428
429 $this->put($this->theA);
430
431 case JSMIN_ACT_BUF : // N.B. possible fallthrough from above
432
433 // Copy B to A
434
435 $tmpA = $this->theA = $this->theB;
436
437 // Treating a string as a single char : outputting it whole
438 // Note that the string-opening char (" or ') is memorized in B
439
440 if ($tmpA == '\'' || $tmpA == '"') {
441
442 while (true) {
443
444 // Output string contents
445
446 $this->put($tmpA);
447
448 // Get next character, watching out for termination of the current string,
449 // new line & co (then the string is not terminated !), or a backslash
450 // (upon which the following char is directly output to serve the escape mechanism)
451
452 $tmpA = $this->theA = $this->get();
453
454 if ($tmpA == $this->theB) {
455
456 // String terminated
457
458 break; // from while(true)
459 }
460
461 // else
462
463 if (ord($tmpA) <= ORD_NL) {
464
465 // Whoopsie
466
467 //throw new UnterminatedStringLiteralJSMinException();
468 trigger_error('UnterminatedStringLiteral', E_USER_ERROR);
469 }
470
471 // else
472
473 if ($tmpA == '\\') {
474
475 // Escape next char immediately
476
477 $this->put($tmpA);
478 $tmpA = $this->theA = $this->get();
479 }
480 }
481 }
482
483 case JSMIN_ACT_IMM : // N.B. possible fallthrough from above
484
485 // Get the next B
486
487 $this->theB = $this->next();
488
489 // Special case of recognising regular expressions (beginning with /) that are
490 // preceded by '(', ',' or '='
491
492 $tmpA = $this->theA;
493
494 if ($this->theB == '/' && ($tmpA == '(' || $tmpA == ',' || $tmpA == '=')) {
495
496 // Output the two successive chars
497
498 $this->put($tmpA);
499 $this->put($this->theB);
500
501 // Look for the end of the RE literal, watching out for escaped chars or a control /
502 // end of line char (the RE literal then being unterminated !)
503
504 while (true) {
505
506 $tmpA = $this->theA = $this->get();
507
508 if ($tmpA == '/') {
509
510 // RE literal terminated
511
512 break; // from while(true)
513 }
514
515 // else
516
517 if ($tmpA == '\\') {
518
519 // Escape next char immediately
520
521 $this->put($tmpA);
522 $tmpA = $this->theA = $this->get();
523 }
524 else if (ord($tmpA) <= ORD_NL) {
525
526 // Whoopsie
527
528 //throw new UnterminatedRegExpLiteralJSMinException();
529 trigger_error('UnterminatedRegExpLiteral', E_USER_ERROR);
530 }
531
532 // Output RE characters
533
534 $this->put($tmpA);
535 }
536
537 // Move forward after the RE literal
538
539 $this->theB = $this->next();
540 }
541
542 break;
543 default :
544 //throw new JSMinException('Expected a JSMin::ACT_* constant in action().');
545 trigger_error('Expected a JSMin::ACT_* constant in action()', E_USER_ERROR);
546 }
547 }
548
564 function minify() {
565
566 // Initialize A and run the first (minimal) action
567
568 $this->theA = "\n";
569 $this->action(JSMIN_ACT_IMM);
570
571 // Proceed all the way to the end of the input file
572
573 while ($this->theA !== EOF) {
574
575 switch ($this->theA) {
576
577 case ' ' :
578
579 if (JSMin::isAlphaNum($this->theB)) {
580 $this->action(JSMIN_ACT_FULL);
581 }
582 else {
583 $this->action(JSMIN_ACT_BUF);
584 }
585
586 break;
587 case "\n" :
588
589 switch ($this->theB) {
590
591 case '{' : case '[' : case '(' :
592 case '+' : case '-' :
593
594 $this->action(JSMIN_ACT_FULL);
595
596 break;
597 case ' ' :
598
599 $this->action(JSMIN_ACT_IMM);
600
601 break;
602 default :
603
604 if (JSMin::isAlphaNum($this->theB)) {
605 $this->action(JSMIN_ACT_FULL);
606 }
607 else {
608 $this->action(JSMIN_ACT_BUF);
609 }
610
611 break;
612 }
613
614 break;
615 default :
616
617 switch ($this->theB) {
618
619 case ' ' :
620
621 if (JSMin::isAlphaNum($this->theA)) {
622
623 $this->action(JSMIN_ACT_FULL);
624 break;
625 }
626
627 // else
628
629 $this->action(JSMIN_ACT_IMM);
630
631 break;
632 case "\n" :
633
634 switch ($this->theA) {
635
636 case '}' : case ']' : case ')' : case '+' :
637 case '-' : case '"' : case '\'' :
638
639 $this->action(JSMIN_ACT_FULL);
640
641 break;
642 default :
643
644 if (JSMin::isAlphaNum($this->theA)) {
645 $this->action(JSMIN_ACT_FULL);
646 }
647 else {
648 $this->action(JSMIN_ACT_IMM);
649 }
650
651 break;
652 }
653
654 break;
655 default :
656
657 $this->action(JSMIN_ACT_FULL);
658
659 break;
660 }
661
662 break;
663 }
664 }
665
666 if ($this->isString) {
667 return $this->out;
668
669 }
670 }
671
682 function JSMin($inFileName = '-', $outFileName = '-', $comments = NULL) {
683 if ($outFileName === FALSE) {
684 $this->JSMin_String($inFileName, $comments);
685 }
686 else {
687 $this->JSMin_File($inFileName, $outFileName, $comments);
688 }
689 }
690
691 function JSMin_File($inFileName = '-', $outFileName = '-', $comments = NULL) {
692
693 // Recuperate input and output streams.
694 // Use STDIN and STDOUT by default, if they are defined (CLI mode) and no file names are provided
695
696 if ($inFileName == '-') $inFileName = 'php://stdin';
697 if ($outFileName == '-') $outFileName = 'php://stdout';
698
699 /*try {
700
701 $this->in = new SplFileObject($inFileName, 'rb', TRUE);
702 }
703 catch (Exception $e) {
704
705 throw new FileOpenFailedJSMinException(
706 'Failed to open "'.$inFileName.'" for reading only.'
707 );
708 }
709
710 try {
711
712 $this->out = new SplFileObject($outFileName, 'wb', TRUE);
713 }
714 catch (Exception $e) {
715
716 throw new FileOpenFailedJSMinException(
717 'Failed to open "'.$outFileName.'" for writing only.'
718 );
719 }
720 */
721 $this->in = fopen($inFileName, 'rb');
722 if (!$this->in) {
723 trigger_error('Failed to open "'.$inFileName, E_USER_ERROR);
724 }
725 $this->out = fopen($outFileName, 'wb');
726 if (!$this->out) {
727 trigger_error('Failed to open "'.$outFileName, E_USER_ERROR);
728 }
729
730 // Present possible initial comments
731
732 if ($comments !== NULL) {
733 foreach ($comments as $comm) {
734 $this->out->fwrite('// '.str_replace("\n", " ", $comm)."\n");
735 }
736 }
737
738 }
739
740 function JSMin_String($inString, $comments = NULL) {
741 $this->in = $inString;
742 $this->out = '';
743 $this->inLength = strlen($inString);
744 $this->inPos = 0;
745 $this->isString = true;
746
747 if ($comments !== NULL) {
748 foreach ($comments as $comm) {
749 $this->out .= '// '.str_replace("\n", " ", $comm)."\n";
750 }
751 }
752 }
753}
754
760?>
const ORD_NL
Some ASCII character ordinals.
Definition: JSMin_lib.php:99
const ORD_z
Definition: JSMin_lib.php:104
const JSMIN_ACT_BUF
Constant describing an action() : Copy B to A.
Definition: JSMin_lib.php:156
const ORD_cA
Definition: JSMin_lib.php:101
const ORD_0
Definition: JSMin_lib.php:105
const ORD_9
Definition: JSMin_lib.php:106
const ORD_a
Definition: JSMin_lib.php:103
const EOF
How fgetc() reports an End Of File.
Definition: JSMin_lib.php:92
const JSMIN_ACT_IMM
Constant describing an action() : Get the next B.
Definition: JSMin_lib.php:162
const JSMIN_ACT_FULL
Constant describing an action() : Output A.
Definition: JSMin_lib.php:150
const ORD_space
Definition: JSMin_lib.php:100
const ORD_cZ
Definition: JSMin_lib.php:102
A JSMin exception indicating that a file provided for input or output could not be properly opened.
Definition: JSMin_lib.php:122
Generic exception class related to JSMin.
Definition: JSMin_lib.php:115
Main JSMin application class.
Definition: JSMin_lib.php:175
$inLength
variables used for string-based parsing
Definition: JSMin_lib.php:204
JSMin_String($inString, $comments=NULL)
Definition: JSMin_lib.php:740
next()
Get the next character from the input stream, excluding comments.
Definition: JSMin_lib.php:331
put($c)
Adds a char to the output steram / string.
Definition: JSMin_lib.php:312
JSMin_File($inFileName='-', $outFileName='-', $comments=NULL)
Definition: JSMin_lib.php:691
peek()
Get the next character from the input stream, without gettng it.
Definition: JSMin_lib.php:283
minify()
Run the JSMin application : minify some JS code.
Definition: JSMin_lib.php:564
action($action)
Do something !
Definition: JSMin_lib.php:418
JSMin($inFileName='-', $outFileName='-', $comments=NULL)
Prepare a new JSMin application.
Definition: JSMin_lib.php:682
isAlphaNum($c)
Indicates whether a character is alphanumeric or _, $, \ or non-ASCII.
Definition: JSMin_lib.php:214
A JSMin exception indicating that an unterminated comment was encountered in input.
Definition: JSMin_lib.php:129
A JSMin exception indicatig that an unterminated regular expression lieteral was encountered in input...
Definition: JSMin_lib.php:143
A JSMin exception indicatig that an unterminated string literal was encountered in input.
Definition: JSMin_lib.php:136