001: package com.quadcap.util;
002:
003: /* Copyright 1997 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: //-//#ifdef JDK11
042: //-import com.sun.java.util.collections.ArrayList;
043: //-import com.sun.java.util.collections.Collections;
044: //-import com.sun.java.util.collections.Comparator;
045: //#endif
046: import java.util.ArrayList;
047: import java.util.Collections;
048: import java.util.Comparator;
049: import java.util.HashMap;
050: import java.util.Hashtable;
051: import java.util.List;
052: import java.util.Properties;
053: import java.util.Vector;
054:
055: import java.io.ByteArrayInputStream;
056: import java.io.ByteArrayOutputStream;
057: import java.io.File;
058: import java.io.FileInputStream;
059: import java.io.FileOutputStream;
060: import java.io.IOException;
061: import java.io.InputStream;
062: import java.io.OutputStream;
063: import java.io.PrintStream;
064:
065: import java.text.Collator;
066:
067: import java.lang.reflect.Array;
068:
069: /**
070: * This class aggregates a bunch of various string manipulation utilities.
071: *
072: * @author Stan Bailes
073: */
074: public class Util {
075: /**
076: * Split a string into a vector of elements.
077: */
078: public static Vector split(String s, char delim) {
079: return split(s, delim, -1);
080: }
081:
082: public static Vector split(String s, char delim, int cnt) {
083: Vector v = new Vector();
084: StringBuffer sb = new StringBuffer();
085: for (int i = 0; i < s.length(); i++) {
086: char c = s.charAt(i);
087: if (c == delim && (cnt < 0 || v.size() + 1 < cnt)) {
088: if (sb.length() > 0) {
089: v.addElement(sb.toString());
090: sb = new StringBuffer();
091: }
092: } else {
093: sb.append(c);
094: }
095: }
096: if (sb.length() > 0) {
097: v.addElement(sb.toString());
098: }
099: while (v.size() < cnt) {
100: v.addElement(new String(""));
101: }
102: return v;
103: }
104:
105: public static Hashtable parseArgs(String args[]) {
106: Hashtable t = new Hashtable();
107: int i = 0;
108: Vector a = new Vector();
109: while (i < args.length && args[i].startsWith("-")) {
110: String arg = args[i];
111: if (arg.charAt(0) == '-') {
112: Vector v = (Vector) t.get(arg);
113: if (v == null)
114: v = new Vector();
115: v.addElement(args[i + 1]);
116: t.put(arg.substring(1), v);
117: i++;
118: } else {
119: a.addElement(arg);
120: }
121: i++;
122: }
123: t.put("", a);
124: return t;
125: }
126:
127: public static String readFile(String filename) {
128: File f = new File(filename);
129: if (f.exists()) {
130: try {
131: FileInputStream is = new FileInputStream(f);
132: StringBuffer sb = new StringBuffer();
133: int c;
134: while ((c = is.read()) >= 0)
135: sb.append((char) c);
136: String r = sb.toString();
137: return r;
138: } catch (IOException e) {
139: Debug.println("Util.readFile(" + filename + ") "
140: + "Got IOException: " + e.toString());
141: }
142: }
143: return null;
144: }
145:
146: public static char[] hexMap = { '0', '1', '2', '3', '4', '5', '6',
147: '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
148:
149: public static String strBytes(byte[] buf, int offset, int len) {
150: if (buf == null || len == 0)
151: return "<null>";
152: StringBuffer sb = new StringBuffer();
153: for (int i = 0; i < len; i++) {
154: if ((i % 16) == 0 && (len - i > 12 || i > 0)) {
155: if (i > 0) {
156: sb.append(' ');
157: sb.append(' ');
158: for (int j = (i - 1) & ~15; j < i; j++) {
159: byte c = buf[offset + j];
160: if (c >= 0x20 && c <= 0x7f)
161: sb.append((char) c);
162: else
163: sb.append('.');
164: }
165: }
166: sb.append('\n');
167: }
168: byte b = buf[offset + i];
169: sb.append(hexMap[(b >> 4) & 0xf]);
170: sb.append(hexMap[b & 0xf]);
171: sb.append(' ');
172: }
173: if (len > 16)
174: for (int j = len; (j & 15) != 0; j++)
175: sb.append(" ");
176: sb.append(" ");
177: for (int j = (len - 1) & ~15; j < len; j++) {
178: byte c = buf[offset + j];
179: if (c >= 0x20 && c <= 0x7f)
180: sb.append((char) c);
181: else
182: sb.append('.');
183: }
184: return sb.toString();
185: }
186:
187: public static String hexBytes(byte[] buf) {
188: if (buf == null)
189: return "<null>";
190: return hexBytes(buf, 0, buf.length);
191: }
192:
193: public static String hexBytes(byte[] buf, int off, int len) {
194: if (buf == null)
195: return "<null>";
196: StringBuffer sb = new StringBuffer();
197: for (int i = off; i < off + len; i++) {
198: if (i >= buf.length) {
199: sb.append("###### OVERRUN ######");
200: break;
201: }
202: byte b = buf[i];
203: sb.append(hexMap[(b >> 4) & 0xf]);
204: sb.append(hexMap[b & 0xf]);
205: }
206: return sb.toString();
207: }
208:
209: public static String hexInts(byte[] buf) {
210: return hexInts(buf, 0, buf.length);
211: }
212:
213: public static String hexInts(byte[] buf, int off, int len) {
214: if (buf == null)
215: return "<null>";
216: StringBuffer sb = new StringBuffer();
217: for (int i = off; i < off + len; i++) {
218: if (i >= buf.length) {
219: sb.append("###### OVERRUN ######");
220: break;
221: }
222: byte b = buf[i];
223: sb.append(hexMap[(b >> 4) & 0xf]);
224: sb.append(hexMap[b & 0xf]);
225: if ((((i + 1) - off) % 4) == 0)
226: sb.append(' ');
227: }
228: return sb.toString();
229: }
230:
231: public static String strBytes(byte[] buf) {
232: if (buf == null)
233: return "<null>";
234: return strBytes(buf, 0, buf.length);
235: }
236:
237: public static boolean boolProperty(String s) {
238: return Boolean.getBoolean(s);
239: }
240:
241: public static int intProperty(String s, int defVal) {
242: String v = System.getProperty(s);
243: return v == null ? defVal : Integer.parseInt(v);
244: }
245:
246: public static String strProperty(String s, String defVal) {
247: String v = System.getProperty(s);
248: return v == null ? defVal : v;
249: }
250:
251: public static byte[] bytes(String s) {
252: byte[] buf = new byte[s.length()];
253: s.getBytes(0, buf.length, buf, 0);
254: return buf;
255: }
256:
257: /**
258: * To hell with character encodings ;-)
259: */
260: public static byte[] strCharsAsBytes(String s) {
261: byte[] buf = new byte[s.length() * 2];
262: char[] cbuf = s.toCharArray();
263: charsToBytes(cbuf, 0, buf, 0, s.length());
264: return buf;
265: }
266:
267: public static void bytesToChars(byte[] bbuf, int boff, char[] cbuf,
268: int coff, int clen) {
269: int clim = coff + clen;
270: while (coff < clim) {
271: int c1 = bbuf[boff++] & 0xff;
272: int c2 = bbuf[boff++] & 0xff;
273: cbuf[coff++] = (char) ((c1 << 8) | c2);
274: }
275: }
276:
277: public static void charsToBytes(char[] cbuf, int coff, byte[] bbuf,
278: int boff, int clen) {
279: int clim = coff + clen;
280: while (coff < clim) {
281: char c = cbuf[coff++];
282: bbuf[boff++] = (byte) (c >> 8);
283: bbuf[boff++] = (byte) (c & 0xff);
284: }
285: }
286:
287: /**
288: * Convert an int to a byte array, MSB first
289: *
290: * @param i the int value
291: */
292: public static byte[] bytes(int i) {
293: byte[] buf = new byte[4];
294: buf[0] = (byte) ((i >> 24) & 0xff);
295: buf[1] = (byte) ((i >> 16) & 0xff);
296: buf[2] = (byte) ((i >> 8) & 0xff);
297: buf[3] = (byte) ((i >> 0) & 0xff);
298: return buf;
299: }
300:
301: /**
302: * Convert a long to a byte array, MSB first.
303: *
304: * @param i the long value
305: */
306: public static byte[] bytes(long i) {
307: byte[] buf = new byte[8];
308: buf[0] = (byte) ((i >> 56) & 0xff);
309: buf[1] = (byte) ((i >> 48) & 0xff);
310: buf[2] = (byte) ((i >> 40) & 0xff);
311: buf[3] = (byte) ((i >> 32) & 0xff);
312: buf[4] = (byte) ((i >> 24) & 0xff);
313: buf[5] = (byte) ((i >> 16) & 0xff);
314: buf[6] = (byte) ((i >> 8) & 0xff);
315: buf[7] = (byte) ((i >> 0) & 0xff);
316: return buf;
317: }
318:
319: /**
320: * Convert a byte array which represents an integer into an integer.
321: *
322: * @param buf the byte array, MSB first.
323: * @return the integer value stored in the byte array.
324: */
325: public static int integer(byte[] buf) {
326: int ret = 0;
327: for (int i = 0; i < buf.length; i++) {
328: ret <<= 8;
329: ret |= (buf[i] & 0xff);
330: }
331: return ret;
332: }
333:
334: /**
335: * Extract an integer from four bytes in a byte array.
336: *
337: * @param buf the byte array
338: * @param pos the offset in the array of the first (MSB) byte of the int
339: * @return the integer value stored in the byte array.
340: */
341: public static int integer(byte[] buf, int pos) {
342: int b1 = buf[pos++] & 0xff;
343: int b2 = buf[pos++] & 0xff;
344: int b3 = buf[pos++] & 0xff;
345: int b4 = buf[pos++] & 0xff;
346: int val = (b1 << 24) + (b2 << 16) + (b3 << 8) + (b4 << 0);
347: return val;
348: }
349:
350: public static void putInt(byte[] buf, int pos, int val) {
351: buf[pos++] = (byte) ((val >>> 24) & 0xff);
352: buf[pos++] = (byte) ((val >>> 16) & 0xff);
353: buf[pos++] = (byte) ((val >>> 8) & 0xff);
354: buf[pos] = (byte) ((val) & 0xff);
355: }
356:
357: public static void putLong(byte[] buf, int pos, long val) {
358: buf[pos++] = (byte) ((val >>> 56) & 0xff);
359: buf[pos++] = (byte) ((val >>> 48) & 0xff);
360: buf[pos++] = (byte) ((val >>> 40) & 0xff);
361: buf[pos++] = (byte) ((val >>> 32) & 0xff);
362: buf[pos++] = (byte) ((val >>> 24) & 0xff);
363: buf[pos++] = (byte) ((val >>> 16) & 0xff);
364: buf[pos++] = (byte) ((val >>> 8) & 0xff);
365: buf[pos] = (byte) ((val) & 0xff);
366: }
367:
368: /**
369: * Convert a byte array which represents a long into a long.
370: *
371: * @param buf the byte array, MSB first.
372: * @return the long value stored in the byte array.
373: */
374: public final static long bytesToLong(byte[] buf) {
375: return bytesToLong(buf, 0);
376: }
377:
378: /**
379: * Convert a byte array which represents a long into a long.
380: *
381: * @param buf the byte array, MSB first.
382: * @return the long value stored in the byte array.
383: */
384: public final static long bytesToLong(byte[] buf, int offset) {
385: long ret = 0;
386: int lim = offset + 8;
387: for (int i = offset; i < buf.length && i < lim; i++) {
388: ret <<= 8;
389: ret |= (buf[i] & 0xff);
390: }
391: return ret;
392: }
393:
394: /**
395: * Byte-array comparison.
396: *
397: * @param k1 the byte array containing key 1.
398: * @param s1 the starting offset of key 1 in <code>k1</code>.
399: * @param c1 the length of key 1.
400: * @param k2 the byte array containing key 2.
401: * @param s2 the starting offset of key 2 in <code>k2</code>.
402: * @param c2 the length of key 2.
403: * @return<p><table cellspacing=2 border=2>
404: * <tr><td>< zero<td>if key1 is less than key2
405: * <tr><td>zero<td>if key1 is equal to key2
406: * <tr><td>> zero<td>if key1 is greater than key2</table>
407: */
408: public static int compareBytes(byte[] k1, int s1, int c1,
409: byte[] k2, int s2, int c2) {
410: int l1 = s1 + c1;
411: int l2 = s2 + c2;
412: while (s1 < l1 && s2 < l2) {
413: if (k1[s1] < k2[s2])
414: return -1;
415: if (k1[s1] > k2[s2])
416: return 1;
417: s1++;
418: s2++;
419: }
420: if (c1 < c2)
421: return -1;
422: if (c1 > c2)
423: return 1;
424: return 0;
425: }
426:
427: public static int compareBytes(byte[] b1, byte[] b2) {
428: return compareBytes(b1, 0, b1.length, b2, 0, b2.length);
429: }
430:
431: /**
432: * Return a File object corresponding to the specified file name.
433: * If the name is relative, it is located relative to the user's
434: * current directory. This is helpful for the case when we run
435: * as a service from the /winnt/system32 directory and want to
436: * open files relative to our install root.
437: *
438: * @param name the file name
439: * @return the file
440: */
441: public static File userFile(String name) {
442: File f = new File(name);
443: f = new File(f.getAbsolutePath());
444: return f;
445: }
446:
447: /**
448: * Like File.list(), but returns directories first, and sorts alpha
449: */
450: public static String[] listFiles(final File f) {
451: String[] s = f.list();
452: if (s != null) {
453: final Collator col = Collator.getInstance();
454: Comparator c = new Comparator() {
455: public int compare(Object a, Object b) {
456: File fa = new File(f, a.toString());
457: File fb = new File(f, b.toString());
458: if (fa.isDirectory() && !fb.isDirectory())
459: return -1;
460: if (!fa.isDirectory() && fb.isDirectory())
461: return 1;
462: return col.compare(a.toString(), b.toString());
463: }
464:
465: public boolean equals(Object obj) {
466: return false;
467: }
468: };
469: ArrayList a = new ArrayList();
470: for (int i = 0; i < s.length; i++)
471: a.add(s[i]);
472: Collections.sort(a, c);
473: for (int i = 0; i < s.length; i++)
474: s[i] = (String) a.get(i);
475: }
476: return s;
477: }
478:
479: public static String getStackTrace(Throwable t) {
480: ByteArrayOutputStream bos = new ByteArrayOutputStream();
481: PrintStream ps = new PrintStream(bos);
482: t.printStackTrace(ps);
483: ps.flush();
484: return bos.toString();
485: }
486:
487: static HashMap traces = new HashMap();
488: static int lastTrace = 0;
489:
490: /**
491: * Return a string showing the current stack trace.
492: */
493: public static String stackTrace() {
494: return stackTrace(new Exception(""), true);
495: }
496:
497: public static String stackTrace(boolean condense) {
498: return stackTrace(new Exception(""), condense);
499: }
500:
501: /**
502: * Return a string showing the current stack trace.
503: */
504: public static String stackTrace(Throwable e, boolean condense) {
505: ByteArrayOutputStream bos = new ByteArrayOutputStream();
506: PrintStream ps = new PrintStream(bos);
507: e.printStackTrace(ps);
508: ps.flush();
509: ByteArrayInputStream bis = new ByteArrayInputStream(bos
510: .toByteArray());
511: StringBuffer sb = new StringBuffer();
512: int state = 1;
513: while (state >= 0) {
514: int c = bis.read();
515: if (c < 0)
516: state = -1;
517: switch (state) {
518: case -1:
519: break;
520: case 0:
521: if (c == '\n')
522: state++;
523: break;
524: case 1:
525: if (c == '\n')
526: state++;
527: break;
528: case 2:
529: if (c == 'a')
530: state++;
531: break;
532: case 3:
533: if (c == 't')
534: state++;
535: break;
536: case 4:
537: if (c == ' ')
538: state++;
539: break;
540: case 5:
541: sb.append((char) c);
542: if (c == '\n')
543: state = 2;
544: break;
545: }
546: }
547: String s = sb.toString();
548: Integer num = (Integer) traces.get(s);
549: if (num == null) {
550: num = new Integer(++lastTrace);
551: traces.put(s, num);
552: s = "Trace " + num + ": " + s;
553: } else {
554: s = "Trace " + num + (condense ? "" : (": " + s));
555: }
556: return s;
557: }
558:
559: public static void copyStream(InputStream in, OutputStream out)
560: throws IOException {
561: byte[] buf = new byte[4096];
562: int cnt;
563: while ((cnt = in.read(buf)) > 0)
564: out.write(buf, 0, cnt);
565: }
566:
567: public static int execCommand(String cmd, OutputStream out,
568: OutputStream err) {
569: int ret = -1;
570: try {
571: Runtime r = Runtime.getRuntime();
572: Process p = r.exec(cmd);
573: return waitFor(p, out, err);
574: } catch (IOException e) {
575: Debug.print(e);
576: ret = -1;
577: }
578: return ret;
579: }
580:
581: public static int execCommand(String[] cmdarray, OutputStream out,
582: OutputStream err) {
583: int ret = -1;
584: try {
585: Runtime r = Runtime.getRuntime();
586: Process p = r.exec(cmdarray);
587: return waitFor(p, out, err);
588: } catch (IOException e) {
589: Debug.print(e);
590: ret = -1;
591: }
592: return ret;
593: }
594:
595: public static int waitFor(Process p, OutputStream out,
596: OutputStream err) throws IOException {
597: Thread it = makeCopyThread(p.getInputStream(), out);
598: Thread et = makeCopyThread(p.getErrorStream(), err);
599: it.start();
600: et.start();
601: int ret = Util.waitFor(p);
602: Util.join(it);
603: Util.join(et);
604: return ret;
605: }
606:
607: public static int execCommand(String cmd, OutputStream out) {
608: return execCommand(cmd, out, out);
609: }
610:
611: public static String execCommand(String cmd) {
612: ByteArrayOutputStream b = new ByteArrayOutputStream();
613: execCommand(cmd, b);
614: return b.toString();
615: }
616:
617: public static String execCommand(String[] cmd) {
618: ByteArrayOutputStream b = new ByteArrayOutputStream();
619: execCommand(cmd, b, b);
620: return b.toString();
621: }
622:
623: public static String execCommand(String a, String b) {
624: return execCommand(new String[] { a, b });
625: }
626:
627: public static String execCommand(String a, String b, String c) {
628: return execCommand(new String[] { a, b, c });
629: }
630:
631: /**
632: * Create a thread which copies bytes from an input stream to
633: * an output stream until end of file is reached.
634: */
635: public static Thread makeCopyThread(final InputStream in,
636: final OutputStream out) {
637: Thread t = new Thread() {
638: boolean terminate = false;
639:
640: public void run() {
641: int c;
642: try {
643: while (!terminate && (c = in.read()) >= 0)
644: out.write(c);
645: } catch (IOException e) {
646: Debug.print(e);
647: }
648: }
649:
650: public void terminate() {
651: this .terminate = true;
652: }
653: };
654: return t;
655: }
656:
657: /**
658: * Utility to sleep without having to worry about catching
659: * InterruptedException.
660: *
661: * @param ms milliseconds to sleep.
662: */
663: public static final void sleep(long ms) {
664: try {
665: Thread.sleep(ms);
666: } catch (InterruptedException e) {
667: Debug.print(e);
668: }
669: }
670:
671: /**
672: * Utility to join without having to worry about catching
673: * InterruptedException.
674: *
675: * @param t the thread to wait for
676: */
677: public static final void join(Thread t) {
678: try {
679: t.join();
680: } catch (InterruptedException e) {
681: Debug.print(e);
682: }
683: }
684:
685: /**
686: * Utility to wait for a process without having to worry about catching
687: * InterruptedException
688: *
689: * @param p the process to wait for
690: */
691: public static final int waitFor(Process p) {
692: try {
693: return p.waitFor();
694: } catch (InterruptedException e) {
695: Debug.print(e);
696: return -1;
697: }
698: }
699:
700: /**
701: * Parse a semicolon-separated property list:
702: *
703: * prop1=val1;prop2=val2
704: */
705: public static final Properties parsePropsString(String extraProps) {
706: Properties props = new Properties();
707: Vector v = Util.split(extraProps, ';');
708: for (int i = 0; i < v.size(); i++) {
709: String prop = v.elementAt(i).toString();
710: int idx = prop.indexOf('=');
711: if (idx > 0) {
712: props.setProperty(prop.substring(0, idx), prop
713: .substring(idx + 1));
714: }
715: }
716: return props;
717: }
718:
719: /**
720: * Generic array resizer
721: */
722: public static Object checkCapacity(Object array, int desiredcap) {
723: int len = Array.getLength(array);
724: if (len < desiredcap) {
725: Class c = array.getClass();
726: Class t = c.getComponentType();
727: Object n = Array.newInstance(t, desiredcap);
728: System.arraycopy(array, 0, n, 0, len);
729: array = n;
730: }
731: return array;
732: }
733:
734: /**
735: * Parse a comma-separated list of integers or integer ranges.
736: *
737: * Example: 1,2
738: * Example: 1,3-5,77
739: *
740: * @return a List of Integers
741: */
742: public static List parseIntList(String s) {
743: List ret = new ArrayList();
744: List tests = Util.split(s, ',');
745:
746: for (int i = 0; i < tests.size(); i++) {
747: int first, last;
748: final String t = tests.get(i).toString();
749: final int idx = t.indexOf('-');
750: if (idx > 0) {
751: first = Integer.parseInt(t.substring(0, idx));
752: last = Integer.parseInt(t.substring(idx + 1));
753: if (last < first)
754: last = first;
755: } else {
756: first = last = Integer.parseInt(t);
757: }
758: for (int test = first; test <= last; test++) {
759: ret.add(new Integer(test));
760: }
761: }
762: return ret;
763: }
764:
765: public static int compareObjects(Object a, Object b) {
766: if (a == null) {
767: return (b == null) ? 0 : -1;
768: } else if (b == null) {
769: return 1;
770: } else if (a instanceof Comparable) {
771: return ((Comparable) a).compareTo(b);
772: } else if (b instanceof Comparable) {
773: return 0 - ((Comparable) b).compareTo(a);
774: } else {
775: return String.valueOf(a).compareTo(String.valueOf(b));
776: }
777: }
778:
779: public static String htmlEscape(String s) {
780: StringBuffer sb = new StringBuffer();
781: for (int i = 0; i < s.length(); i++) {
782: char c = s.charAt(i);
783: switch (c) {
784: case '<':
785: sb.append("<");
786: break;
787: case '>':
788: sb.append(">");
789: break;
790: case '&':
791: sb.append("&");
792: break;
793: default:
794: sb.append(c);
795: break;
796: }
797: }
798: return sb.toString();
799: }
800:
801: }
|