KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > packtag > implementation > JSMin


1 /**
2  * Project pack:tag >> http://packtag.sf.net
3  *
4  * This software is published under the terms of the LGPL
5  * License version 2.1, a copy of which has been included with this
6  * distribution in the 'lgpl.txt' file.
7  *
8  * Last author: $Author: danielgalan $
9  * Last modified: $Date: 2007/04/22 19:04:25 $
10  * Revision: $Revision: 1.1 $
11  *
12  * $Log: JSMin.java,v $
13  * Revision 1.1 2007/04/22 19:04:25 danielgalan
14  * pack.tag moved from subversion to good old CVS
15  *
16  */

17 package net.sf.packtag.implementation;
18
19 import java.io.FileInputStream JavaDoc;
20 import java.io.FileNotFoundException JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.io.OutputStream JavaDoc;
24 import java.io.PushbackInputStream JavaDoc;
25
26
27
28 /**
29  * Pack algorithm for JavaScript
30  *
31  * @author Daniel Galán y Martins
32  * @author John Reilly
33  * @author Douglas Crockford
34  * @version $Revision: 1.1 $
35  *
36  * JSMin.java 2006-02-13
37  *
38  * Copyright (c) 2006 John Reilly (www.inconspicuous.org)
39  *
40  * This work is a translation from C to Java of jsmin.c published by
41  * Douglas Crockford. Permission is hereby granted to use the Java
42  * version under the same conditions as the jsmin.c on which it is
43  * based.
44  *
45  *
46  * jsmin.c 2003-04-21
47  *
48  * Copyright (c) 2002 Douglas Crockford (www.crockford.com)
49  *
50  * Permission is hereby granted, free of charge, to any person obtaining a copy
51  * of this software and associated documentation files (the "Software"), to deal
52  * in the Software without restriction, including without limitation the rights
53  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
54  * copies of the Software, and to permit persons to whom the Software is
55  * furnished to do so, subject to the following conditions:
56  *
57  * The above copyright notice and this permission notice shall be included in
58  * all copies or substantial portions of the Software.
59  *
60  * The Software shall be used for Good, not Evil.
61  *
62  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
63  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
64  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
65  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
66  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
67  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
68  * SOFTWARE.
69  */

70 public class JSMin {
71
72     private static final int EOF = -1;
73
74     private PushbackInputStream JavaDoc in;
75
76     private OutputStream JavaDoc out;
77
78     private int theA;
79
80     private int theB;
81
82
83     public JSMin(InputStream JavaDoc in, OutputStream JavaDoc out) {
84         this.in = new PushbackInputStream JavaDoc(in);
85         this.out = out;
86     }
87
88
89     /**
90      * isAlphanum -- return true if the character is a letter, digit,
91      * underscore, dollar sign, or non-ASCII character.
92      */

93     static boolean isAlphanum(int c) {
94         return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' || c > 126);
95     }
96
97
98     /**
99      * get -- return the next character from stdin. Watch out for lookahead. If
100      * the character is a control character, translate it to a space or
101      * linefeed.
102      */

103     int get() throws IOException JavaDoc {
104         int c = in.read();
105
106         if (c >= ' ' || c == '\n' || c == EOF) {
107             return c;
108         }
109
110         if (c == '\r') {
111             return '\n';
112         }
113
114         return ' ';
115     }
116
117
118     /**
119      * Get the next character without getting it.
120      */

121     int peek() throws IOException JavaDoc {
122         int lookaheadChar = in.read();
123         in.unread(lookaheadChar);
124         return lookaheadChar;
125     }
126
127
128     /**
129      * next -- get the next character, excluding comments. peek() is used to see
130      * if a '/' is followed by a '/' or '*'.
131      */

132     int next() throws IOException JavaDoc, UnterminatedCommentException {
133         int c = get();
134         if (c == '/') {
135             switch (peek()) {
136                 case '/':
137                     for (;;) {
138                         c = get();
139                         if (c <= '\n') {
140                             return c;
141                         }
142                     }
143
144                 case '*':
145                     get();
146                     for (;;) {
147                         switch (get()) {
148                             case '*':
149                                 if (peek() == '/') {
150                                     get();
151                                     return ' ';
152                                 }
153                                 break;
154                             case EOF:
155                                 throw new UnterminatedCommentException();
156                         }
157                     }
158
159                 default:
160                     return c;
161             }
162
163         }
164         return c;
165     }
166
167
168     /**
169      * action -- do something! What you do is determined by the argument: 1
170      * Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
171      * (Delete A). 3 Get the next B. (Delete B). action treats a string as a
172      * single character. Wow! action recognizes a regular expression if it is
173      * preceded by ( or , or =.
174      */

175
176     void action(int d) throws IOException JavaDoc, UnterminatedRegExpLiteralException, UnterminatedCommentException, UnterminatedStringLiteralException {
177         switch (d) {
178             case 1:
179                 out.write(theA);
180             case 2:
181                 theA = theB;
182
183                 if (theA == '\'' || theA == '"') {
184                     for (;;) {
185                         out.write(theA);
186                         theA = get();
187                         if (theA == theB) {
188                             break;
189                         }
190                         if (theA <= '\n') {
191                             throw new UnterminatedStringLiteralException();
192                         }
193                         if (theA == '\\') {
194                             out.write(theA);
195                             theA = get();
196                         }
197                     }
198                 }
199
200             case 3:
201                 theB = next();
202                 if (theB == '/' && (theA == '(' || theA == ',' || theA == '=')) {
203                     out.write(theA);
204                     out.write(theB);
205                     for (;;) {
206                         theA = get();
207                         if (theA == '/') {
208                             break;
209                         }
210                         else if (theA == '\\') {
211                             out.write(theA);
212                             theA = get();
213                         }
214                         else if (theA <= '\n') {
215                             throw new UnterminatedRegExpLiteralException();
216                         }
217                         out.write(theA);
218                     }
219                     theB = next();
220                 }
221         }
222     }
223
224
225     /**
226      * jsmin -- Copy the input to the output, deleting the characters which are
227      * insignificant to JavaScript. Comments will be removed. Tabs will be
228      * replaced with spaces. Carriage returns will be replaced with linefeeds.
229      * Most spaces and linefeeds will be removed.
230      */

231     public void jsmin() throws IOException JavaDoc, UnterminatedRegExpLiteralException, UnterminatedCommentException, UnterminatedStringLiteralException {
232         theA = '\n';
233         action(3);
234         while(theA != EOF) {
235             switch (theA) {
236                 case ' ':
237                     if (isAlphanum(theB)) {
238                         action(1);
239                     }
240                     else {
241                         action(2);
242                     }
243                     break;
244                 case '\n':
245                     switch (theB) {
246                         case '{':
247                         case '[':
248                         case '(':
249                         case '+':
250                         case '-':
251                             action(1);
252                             break;
253                         case ' ':
254                             action(3);
255                             break;
256                         default:
257                             if (isAlphanum(theB)) {
258                                 action(1);
259                             }
260                             else {
261                                 action(2);
262                             }
263                     }
264                     break;
265                 default:
266                     switch (theB) {
267                         case ' ':
268                             if (isAlphanum(theA)) {
269                                 action(1);
270                                 break;
271                             }
272                             action(3);
273                             break;
274                         case '\n':
275                             switch (theA) {
276                                 case '}':
277                                 case ']':
278                                 case ')':
279                                 case '+':
280                                 case '-':
281                                 case '"':
282                                 case '\'':
283                                     action(1);
284                                     break;
285                                 default:
286                                     if (isAlphanum(theA)) {
287                                         action(1);
288                                     }
289                                     else {
290                                         action(3);
291                                     }
292                             }
293                             break;
294                         default:
295                             action(1);
296                             break;
297                     }
298             }
299         }
300         out.flush();
301     }
302
303     class UnterminatedCommentException extends Exception JavaDoc {
304
305         private static final long serialVersionUID = 7971352218559346169L;
306     }
307
308     class UnterminatedStringLiteralException extends Exception JavaDoc {
309
310         private static final long serialVersionUID = 3813645314180522143L;
311     }
312
313     class UnterminatedRegExpLiteralException extends Exception JavaDoc {
314
315         private static final long serialVersionUID = -5088088141334641219L;
316     }
317
318
319     public static void main(String JavaDoc arg[]) {
320         try {
321             JSMin jsmin = new JSMin(new FileInputStream JavaDoc(arg[0]), System.out);
322             jsmin.jsmin();
323         }
324         catch (FileNotFoundException JavaDoc e) {
325             e.printStackTrace();
326         }
327         catch (ArrayIndexOutOfBoundsException JavaDoc e) {
328             e.printStackTrace();
329         }
330         catch (IOException JavaDoc e) {
331             e.printStackTrace();
332         }
333         catch (UnterminatedRegExpLiteralException e) {
334             e.printStackTrace();
335         }
336         catch (UnterminatedCommentException e) {
337             e.printStackTrace();
338         }
339         catch (UnterminatedStringLiteralException e) {
340             e.printStackTrace();
341         }
342     }
343
344 }
345
Popular Tags