/bundles/plugins-trunk/XML/sidekick/ecmascript/parser/Util.java
Java | 699 lines | 388 code | 96 blank | 215 comment | 140 complexity | 6db5ff0d3d272584dcae12618fd43bd7 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
1/*
2 Copyright (c) 2004-2005, The Dojo Foundation
3 All Rights Reserved.
4
5 Licensed under the Academic Free License version 2.1 or above OR the
6 modified BSD license. For more information on Dojo licensing, see:
7
8 http://dojotoolkit.org/community/licensing.shtml <http://dojotoolkit.org/community/licensing.shtml>
9
10 Code donated to the Dojo Foundation by AOL LLC under the terms of
11 the Dojo CCLA (http://dojotoolkit.org/ccla.txt).
12
13 */
14package sidekick.ecmascript.parser;
15
16import java.util.*;
17import java.util.logging.Level;
18import java.io.*;
19import java.text.*;
20
21import java.nio.*;
22import java.nio.channels.*;
23import java.nio.charset.*;
24
25
26/**
27 * Collection of useful static utility methods.
28 *
29 *
30 * @since JDK 1.4
31 */
32public class Util extends Object {
33
34 /**
35 * Converts milliseconds to some more human readable representation.
36 *
37 * @param millis
38 * An amount of elapsed milliseconds
39 * @return A human readable time string
40 */
41 static public final String millisToNice(long millis) {
42 long seconds = millis / 1000;
43 long sec = (seconds % 3600) % 60;
44 long min = (seconds % 3600) / 60;
45 long hour = seconds / 3600;
46 StringBuffer strbuf = new StringBuffer(60);
47 strbuf.append(" [ ");
48 if (hour > 0L) {
49 strbuf.append(hour + " h ");
50 }
51 if (min > 0L) {
52 strbuf.append(min + " min ");
53 }
54
55 if (sec > 0L) {
56 strbuf.append(sec + " sec ");
57 }
58
59 strbuf.append((millis % 1000) + " millis");
60 strbuf.append(" ]");
61 return strbuf.toString();
62 }
63
64 /**
65 * Creates an array of strings from a string of comma-separated string
66 * tokens.
67 *
68 * @param aString
69 * string containing tokens separated by ","
70 * @return array containing string tokens, can be null if string empty
71 */
72 static public final String[] tokenizeCommaSepString(String aString) {
73 if (aString == null) {
74 return null;
75 }
76 StringTokenizer tokenizer = new StringTokenizer(aString, ",");
77 String[] result = null;
78
79 int n = tokenizer.countTokens();
80
81 if (n > 0) {
82 result = new String[n];
83
84 int i = 0;
85 while (tokenizer.hasMoreTokens()) {
86 result[i] = tokenizer.nextToken().trim();
87 i++;
88 }
89 }
90 return result;
91 }
92
93 /**
94 * Finds the common prefix of two specified strings.
95 *
96 * @param str1
97 * first string
98 * @param str2
99 * second string
100 * @return string which is a common prefix of the two strings, can be empty
101 * string, is never null
102 */
103 static public final String commonPrefix(String str1, String str2) {
104 boolean done = false;
105 StringBuffer buffer = new StringBuffer();
106
107 int i = 0;
108 int n1 = str1.length();
109 int n2 = str2.length();
110
111 while (!done) {
112 char c = str1.charAt(i);
113
114 if (c == str2.charAt(i)) {
115 buffer.append(c);
116 i++;
117 if ((i == n1) || (i == n2)) {
118 done = true;
119 }
120 } else {
121 done = true;
122 }
123 }
124
125 return buffer.toString();
126 }
127
128 /**
129 * Finds the common path prefix of two specified paths. Paths have to be
130 * canonical
131 *
132 * @param path1
133 * first path
134 * @param path2
135 * second path
136 * @return string which is a non-empty common path prefix of the two paths,
137 * or null if they don't have a non-empty common prefix
138 */
139 static public final String commonPathPrefix(String path1, String path2) {
140 boolean done = false;
141 StringBuffer buffer = new StringBuffer();
142
143 StringTokenizer st1 = new StringTokenizer(path1, File.separator, true);
144 StringTokenizer st2 = new StringTokenizer(path2, File.separator, true);
145
146 done = (!(st1.hasMoreTokens() && st2.hasMoreTokens()));
147
148 while (!done) {
149 String p1 = st1.nextToken();
150 String p2 = st2.nextToken();
151
152 if (p1.equals(p2)) {
153 buffer.append(p1);
154 done = (!(st1.hasMoreTokens() && st2.hasMoreTokens()));
155 } else {
156 done = true;
157 }
158 }
159
160 return buffer.length() > 0 ? buffer.toString() : null;
161 }
162
163 static private final ByteBuffer copyBuffer = ByteBuffer
164 .allocateDirect(16 * 1024);
165
166 /**
167 * Does a fast file copy from specified source to specified destination.
168 * Uses nio API introduced in jdk 1.4.
169 *
170 * @param srcFilename
171 * file name of source file
172 * @param dstFilename
173 * file name of copy
174 * @exception IOException
175 * if an I/O error occurs
176 */
177 static public final void copyFile(String srcFilename, String dstFilename)
178 throws IOException {
179 FileInputStream fis = null;
180 FileOutputStream fos = null;
181 FileChannel ifc = null;
182 FileChannel ofc = null;
183
184 Util.copyBuffer.clear();
185
186 try {
187 // Open the file and then get a channel from the stream
188 fis = new FileInputStream(srcFilename);
189 ifc = fis.getChannel();
190 fos = new FileOutputStream(dstFilename);
191 ofc = fos.getChannel();
192
193 int sz = (int) ifc.size();
194
195 int n = 0;
196 while (n < sz) {
197 if (ifc.read(Util.copyBuffer) < 0) {
198 break;
199 }
200 Util.copyBuffer.flip();
201 n += ofc.write(Util.copyBuffer);
202 Util.copyBuffer.compact();
203 }
204
205 } finally {
206 try {
207 if (ifc != null) {
208 ifc.close();
209 } else if (fis != null) {
210 fis.close();
211 }
212 } catch (IOException exc) {
213 }
214
215 try {
216 if (ofc != null) {
217 ofc.close();
218 } else if (fos != null) {
219 fos.close();
220 }
221 } catch (IOException exc) {
222 }
223 }
224
225 // FileInputStream fis = null;
226 // FileOutputStream fos = null;
227 // FileChannel ifc = null;
228 // FileChannel ofc = null;
229
230 // try {
231 // fis = new FileInputStream(srcFilename);
232 // ifc = fis.getChannel();
233 // fos = new FileOutputStream(dstFilename);
234 // ofc = fos.getChannel();
235
236 // int sz = (int)ifc.size();
237 // ifc.transferTo(0, sz, ofc);
238 // } finally {
239 // try {
240 // if(ifc != null){
241 // ifc.close();
242 // } else if(fis != null){
243 // fis.close();
244 // }
245 // } catch(IOException exc){
246 // }
247
248 // try {
249 // if(ofc != null){
250 // ofc.close();
251 // } else if(fos != null){
252 // fos.close();
253 // }
254 // } catch(IOException exc){
255 // }
256 // }
257 }
258
259 static private final DateFormat dateFormat = DateFormat
260 .getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
261
262 /**
263 * Creates a string representing a date stamp of the current system date and
264 * system time. Returned string is suitable to be used in a filename.
265 *
266 * @return string with date/time stamp
267 */
268 static public final String getDateStamp() {
269 String dateStamp = dateFormat.format(new Date());
270 dateStamp = dateStamp.replace(' ', '_');
271 dateStamp = dateStamp.replace(',', '_');
272 dateStamp = dateStamp.replace('/', '-');
273 dateStamp = dateStamp.replace(':', '-');
274
275 return dateStamp;
276 }
277
278 /**
279 * Returns <code>true</code> if specified string is a valid identifier for
280 * java or javascript.
281 *
282 * @param candidate
283 * potential identifier
284 * @return <code>true</code> if it is in fact an identifier
285 */
286 static public final boolean isJavaIdentifier(String candidate) {
287 if ((candidate == null) || (candidate.length() == 0)) {
288 return false;
289 }
290
291 char c = candidate.charAt(0);
292
293 if (!Character.isJavaIdentifierStart(c)) {
294 return false;
295 }
296
297 int n = candidate.length();
298
299 for (int i = 1; i < n; i++) {
300 c = candidate.charAt(i);
301
302 if (!Character.isJavaIdentifierPart(c)) {
303 return false;
304 }
305 }
306
307 return true;
308 }
309
310 /**
311 * Returns <code>true</code> if specified string is a valid composite
312 * reference where each part is a valid identifier for java or javascript.
313 *
314 * @param candidate
315 * potential identifier
316 * @return <code>true</code> if it is in fact a valid composite reference
317 */
318 static public final boolean isValidCompositeReference(String candidate) {
319 if ((candidate == null) || (candidate.length() == 0)) {
320 return false;
321 }
322
323 char c = candidate.charAt(0);
324
325 if (!Character.isJavaIdentifierStart(c)) {
326 return false;
327 }
328
329 int n = candidate.length();
330
331 for (int i = 1; i < n; i++) {
332 c = candidate.charAt(i);
333
334 if (!(Character.isJavaIdentifierPart(c) || (c == '.'))) {
335 return false;
336 }
337 }
338
339 if (c == '.') {
340 return false;
341 }
342
343 return true;
344 }
345
346 /**
347 * Returns <code>true</code> if specified string is whitespace
348 *
349 * @param candidate
350 * potential whitespace
351 * @return <code>true</code> if it is in fact whitespace
352 */
353 static public final boolean isWhitespace(String candidate) {
354 int n = candidate.length();
355
356 for (int i = 0; i < n; i++) {
357 char c = candidate.charAt(i);
358
359 if (!Character.isWhitespace(c)) {
360 return false;
361 }
362 }
363
364 return true;
365 }
366
367 /**
368 * Returns <code>true</code> if specified string is a mixed case string
369 * with case mixing happening in the middle of the string (starting with
370 * uppercase char and continuing with all lowercase chars does count).
371 *
372 * @param candidate
373 * potential mixed case
374 * @return <code>true</code> if it is in fact mixed case
375 */
376 static public final boolean isLikelyIdentifier(String candidate) {
377 int n = candidate.length();
378
379 if (n < 3) {
380 return false;
381 }
382
383 boolean hasLower = false;
384 boolean hasUpper = false;
385 boolean hasUnderscore = false;
386 int nUpper = Character.isUpperCase(candidate.charAt(0)) ? 1 : 0;
387
388 for (int i = 1; i < n; i++) {
389 char c = candidate.charAt(i);
390
391 if (Character.isLowerCase(c)) {
392 hasLower = true;
393 } else if (Character.isUpperCase(c)) {
394 hasUpper = true;
395 nUpper++;
396 } else if (c == '_') {
397 hasUnderscore = true;
398 }
399 }
400
401 return (hasLower && hasUpper) || hasUnderscore
402 || (nUpper == candidate.length());
403 }
404
405 /**
406 * Replaces occurences of substring <code>sub</code> with string
407 * <code>with</code> in specified string.
408 *
409 * @param s
410 * string for replacement
411 * @param sub
412 * substring to replace
413 * @param with
414 * substring to take its place
415 * @return new string with replacements done
416 */
417 static public String replaceString(String s, String sub, String with) {
418 int c = 0;
419 int i = s.indexOf(sub, c);
420 if (i == -1) {
421 return s;
422 }
423
424 StringBuffer buf = new StringBuffer(s.length() + with.length());
425
426 do {
427 buf.append(s.substring(c, i));
428 buf.append(with);
429 c = i + sub.length();
430 } while ((i = s.indexOf(sub, c)) != -1);
431
432 if (c < s.length()) {
433 buf.append(s.substring(c, s.length()));
434 }
435
436 return buf.toString();
437 }
438
439 /**
440 * Replaces occurences of substring <code>sub</code> with string
441 * <code>with</code> in specified string but only if substring is
442 * delimited by non-alphanumeric characters.
443 *
444 * @param s
445 * string for replacement
446 * @param sub
447 * substring to replace
448 * @param with
449 * substring to take its place
450 * @return new string with replacements done
451 */
452 static public String replaceSeparatedString(String s, String sub,
453 String with) {
454 int c = 0;
455 int i = s.indexOf(sub, c);
456 if (i == -1) {
457 return s;
458 }
459
460 StringBuffer buf = new StringBuffer(s.length() + with.length());
461
462 int n = s.length();
463
464 do {
465 buf.append(s.substring(c, i));
466 int beginChar = i > 0 ? s.charAt(i - 1) : -1;
467 int m = i + sub.length();
468 int endChar = m < n ? s.charAt(m) : -1;
469
470 if (((beginChar == -1) || (!Character
471 .isJavaIdentifierStart((char) beginChar)))
472 && ((endChar == -1) || (!Character
473 .isJavaIdentifierPart((char) endChar)))) {
474 buf.append(with);
475 } else {
476 buf.append(sub);
477 }
478 c = i + sub.length();
479 } while ((i = s.indexOf(sub, c)) != -1);
480
481 if (c < s.length()) {
482 buf.append(s.substring(c, s.length()));
483 }
484
485 return buf.toString();
486 }
487
488 /**
489 * Tests if specified string ends with the specified suffix.
490 *
491 * @param aString
492 * string to test
493 * @param aSuffix
494 * suffix.
495 * @return <code>true</code> if the ends in suffix
496 */
497 static public boolean endsWith(String aString, String aSuffix) {
498 if (aString == null) {
499 return aSuffix == null;
500 }
501
502 if (aString.equals("")) {
503 return (aSuffix != null) && aSuffix.equals("");
504 }
505
506 int index = aString.lastIndexOf(aSuffix);
507
508 return index == aString.length() - aSuffix.length();
509 }
510
511 /**
512 * Returns <code>true</code> if the specified filename has wildcard
513 * characters in it, i.e. the name contains either "*" or "?" characters.
514 *
515 * @param filename
516 * filename
517 * @return <code>true</code> if has wildcard characters
518 */
519 static public boolean hasWildcards(String filename) {
520 return (filename.indexOf('*') != -1) || (filename.indexOf('?') != -1);
521 }
522
523 /**
524 * Transforms a user wildcard into a java.util.regex.Pattern pattern string.
525 *
526 * @param wildcard
527 * wildcard string
528 * @return pattern string
529 */
530 static public String wildCard2Pattern(String wildcard) {
531 int n = wildcard.length();
532 StringBuffer regexPatternBuffer = new StringBuffer(n);
533
534 for (int i = 0; i < n; i++) {
535 char c = wildcard.charAt(i);
536 if (c == '*') {
537 regexPatternBuffer.append(".*");
538 } else if (c == '?') {
539 regexPatternBuffer.append('.');
540 } else if (c == '.') {
541 regexPatternBuffer.append("\\.");
542 } else if (c == '$') {
543 regexPatternBuffer.append("\\$");
544 } else {
545 regexPatternBuffer.append(c);
546 }
547 }
548
549 return regexPatternBuffer.toString();
550 }
551
552 /**
553 * Resolves the specified url path to a file on the local file system. Uses
554 * the specified web root and web map aliases to complete the resolution.
555 *
556 * @param urlPath
557 * a url path
558 * @param webroot
559 * directory path on local file system of the web root
560 * @param webmaps
561 * web map aliases
562 * @return a local File instance
563 */
564 static public File resolveWebURL(String urlPath, String webroot, Map webmaps) {
565 File result = null;
566
567 Iterator iter = webmaps.keySet().iterator();
568
569 while (iter.hasNext()) {
570 String key = (String) iter.next();
571
572 if (urlPath.startsWith(key)) {
573 result = new File(((String) webmaps.get(key))
574 + urlPath.substring(key.length()));
575 break;
576 }
577 }
578
579 if (result == null) {
580 result = new File(webroot + urlPath);
581 }
582
583 return result;
584 }
585
586 /**
587 * Reads an input stream completely into memory and returns a CharBuffer
588 * instance with the contents.
589 *
590 * @param inputStream
591 * an input stream
592 * @param decoder
593 * charset decoder
594 * @return CharBuffer instance with the contents
595 * @exception IOException
596 * if reading from inputStream throws IOException
597 */
598 static public CharBuffer readBytes(InputStream inputStream,
599 CharsetDecoder decoder) throws IOException {
600 byte[] buffer = new byte[1024];
601 int b = inputStream.read();
602 int i = 0;
603
604 while (b != -1) {
605 if (i == buffer.length) {
606 byte[] grow = new byte[buffer.length * 2];
607 System.arraycopy(buffer, 0, grow, 0, buffer.length);
608 buffer = grow;
609 }
610 buffer[i++] = (byte) b;
611 b = inputStream.read();
612 }
613
614 return decoder.decode(ByteBuffer.wrap(buffer, 0, i));
615 }
616
617 /**
618 * Escapes a plain text string for html. Doesn't look into those funny
619 * characters like euro symbol, copyright symbol etc.
620 *
621 * @param plainString
622 * plain text string
623 * @return html-escaped string
624 */
625 static public String escape2Html(String plainString) {
626 if (plainString == null) {
627 return null;
628 }
629
630 StringBuffer sb = new StringBuffer();
631 int n = plainString.length();
632
633 int spaceState = 0;
634 int nlState = 0;
635
636 for (int i = 0; i < n; i++) {
637 char c = plainString.charAt(i);
638
639 if (c == ' ') {
640 if (nlState > 0) {
641 if (nlState == 1) {
642 sb.append('\n');
643 } else {
644 sb.append("<p>");
645 }
646 }
647 nlState = 0;
648 if (spaceState == 0) {
649 spaceState = 1;
650 sb.append(c);
651 } else if (spaceState == 1) {
652 spaceState = 0;
653 sb.append(" ");
654 }
655 } else if (c == '\n') {
656 if (nlState == 0) {
657 nlState = 1;
658 } else if (nlState == 1) {
659 nlState = 2;
660 }
661 } else {
662 if (nlState > 0) {
663 if (nlState == 1) {
664 sb.append('\n');
665 } else {
666 sb.append("<p>");
667 }
668 }
669 nlState = 0;
670 spaceState = 0;
671 switch (c) {
672 case '<':
673 sb.append("<");
674 break;
675 case '>':
676 sb.append(">");
677 break;
678 case '&':
679 sb.append("&");
680 break;
681 case '"':
682 sb.append(""");
683 break;
684 case '\'':
685 sb.append("'");
686 break;
687 case '\n':
688 sb.append("<br>");
689 break;
690 default:
691 sb.append(c);
692 break;
693 }
694 }
695 }
696
697 return sb.toString();
698 }
699}