001    /* 
002     * Copyright (c) Holger Pfaff - http://pfaff.ws
003     *
004     * This software maybe used for any purpose provided the
005     * above copyright notice is retained. It is supplied as is.
006     * No warranty expressed or implied - Use at your own risk.
007     */
008    
009    import java.util.Vector;
010    import java.util.Hashtable;
011    import java.util.Enumeration;
012    import java.util.PropertyResourceBundle;
013    
014    /**
015      * (#)Util.java
016      * @author   Holger Pfaff
017      * @version  3.2 19-Mar-2004<br><br>
018      *
019      * Various utility routines for use with j-awt
020      */
021    
022    public class Util {
023    
024      /**
025       * Find index of Object within array
026       *
027       * @return index or -1 on failure
028       *
029       * @param   array   the array to search within
030       * @param   obj   the object to search for
031       */
032      static int indexOf(Object[] array, Object obj) {
033        return indexOf(array, obj, 0);
034      }
035      
036      /**
037       * Find index of Object within array 
038       * starting at a specified index
039       *
040       * @return index or -1 on failure
041       *
042       * @param   array   the array to search within
043       * @param   obj   the object to search for
044       * @param   start   index to start from
045       */
046      static int indexOf(Object[] array, Object obj, int start) {
047        if(array != null) {
048          for(int i = start; i < array.length; ++i) {
049            if(array[i].equals(obj))  return i;
050          }
051        }
052        return -1;
053      }
054      
055      /**
056       * Convert an arbitrary array of Objects into a Vector
057       *
058       * @return resulting Vector
059       *
060       * @param   array   the array to convert
061       */
062      static Vector array2Vector(Object[] array) {
063        return array2Vector(array, 0);
064      }
065      
066      /**
067       * Convert an arbitrary array of Objects into a Vector
068       * starting at a specified index
069       *
070       * @return resulting Vector
071       *
072       * @param   array   the array to convert
073       * @param   start   the index to start from
074       */
075      static Vector array2Vector(Object[] array, int start) {
076        Vector v = new Vector();
077        if(array != null) {
078          for(int i = start; i < array.length; ++i) {
079            v.addElement(array[i]);
080          }
081        }
082        return v;
083      }
084        
085      /**
086       * Convert an arbitrary Enumeration into an Array of Strings
087       *
088       * @return resulting String array
089       *
090       * @param   e   the enumeration to convert
091       */
092      public static String[] enum2Array(Enumeration e) {
093        Vector   v = enum2Vector(e);
094        String[] r = new String[v.size()];
095        for(int i =0; i < r.length; ++i) {
096          r[i] = v.elementAt(i).toString();
097        }
098        return r;
099            }
100      
101      /**
102       * Convert an arbitrary Enumeration into a Vector
103       *
104       * @return resulting Vector
105       *
106       * @param   e   the enumeration to convert
107       */
108      public static Vector enum2Vector(Enumeration e) {
109        Vector r = new Vector();
110        while(e.hasMoreElements()) {
111          r.addElement(e.nextElement());
112        }
113                    return r;
114            }
115      
116      /**
117       * Convert an arbitrary Enumeration into a single String 
118       * separated with a specified delimiter character
119       *
120       * @return resulting String
121       *
122       * @param   e   the enumeration to convert
123       * @param   dl   the delimiter to use
124       */
125      public static String enum2String(Enumeration e, String dl) {
126        String r = e.hasMoreElements() ? e.nextElement().toString() : "";
127        while(e.hasMoreElements()) {
128          r += dl + e.nextElement().toString();
129        }
130                    return r;
131            }
132    
133      /**
134       * Invoke an arbitrary method of an Object<br>
135       * <code>Util.invoke(myclass, "printx hello world")</code> would call 
136       * method printx of object myclass with "printx" "hello" "world" as arguments.
137       * Method printx should be defined as <code>public void printx(Vector argv)</code>
138       *
139       * @param   o   class instance to use
140       * @param   argv   the argument vector as blank separated string
141       */
142      static void invoke(Object o, String argv) {
143        invoke(o, new StringSplitter(argv, " ", false).toVector());
144      }
145      
146      /**
147       * Invoke an arbitrary method of an Object<br>
148       *
149       * @param   o   class instance to use
150       * @param   argv   the arguments as a Vector list
151       */
152      static void invoke(Object o, Vector argv) {
153        try {
154          Class  argt[] = {Vector.class};
155          Object args[] = {argv};
156          o.getClass().getMethod((String) argv.elementAt(0), argt).invoke(o, args);
157        } catch(Exception x) {
158          Debug.debug(Util.class, x); 
159        }
160      }
161    
162      /**
163       * Get contents of a properties file as a Hashtable. Tries to load 
164       * <name>.properties first then <name>_<lang>.properties. If that fails
165       * try to load default lang "en". Depending on JVM used the properties
166       * file has to reside within the jar archive of the current applet
167       *
168       * @return Hashtable containing key/value pairs from properties files
169       *
170       * @param   name   name of properties to load
171       * @param   lang   language of properties to load
172       */
173      static Hashtable getResourceHash(String name, String lang) {
174        Hashtable h = new Hashtable();
175        Util.putResourceHash(name, h, h);
176        if(Util.putResourceHash(name + "_" + lang, h, null) == null) {
177          Util.putResourceHash(name + "_en", h, null);
178        }
179        return h;
180      }
181          
182      /**
183       * Convert content of a specific property file to a hashtable. This method
184       * get called by getResourceHash() to actually do the work.
185       *
186       * @return Hashtable containing key/value pairs from properties file
187       *
188       * @param   name   name of properties to load
189       * @param   h   hashtable to put values in
190       * @param   dh   default hashtable to return in case of errors
191       */
192      static Hashtable putResourceHash(String name, Hashtable h, Hashtable dh) {
193        try {
194          PropertyResourceBundle r = new PropertyResourceBundle(Util.class.getResourceAsStream(name + ".properties"));
195          for(Enumeration e = r.getKeys(); e.hasMoreElements(); ) {
196            String k = (String) e.nextElement();
197            h.put(k, r.getObject(k));
198          }
199          return h;
200        } catch(Exception x) {
201          Debug.debug(Util.class, x);
202          return dh;
203        }
204      }
205    
206      /**
207       * Do shell-style pattern matching for ?, \, [], and * characters.
208       * Negate a class with ^ is also possible. Char ranges should work fine
209       * as long as you stick to ascii chars. As java uses Unicode all other
210       * ranges might not work as expected.
211       * Original version written in C by Rich $alz.
212       *   
213       * @return 0 = false, no match  1 = true, matches  2 = abort, no match, invalid syntax
214       *
215       * @param   text   text to find pattern in
216       * @param   pattern   pattern to search for
217       * 
218       */
219      static int match(String text, String pattern) {
220        char[] T = text.toCharArray(); 
221        char[] P = pattern.toCharArray();
222        int  t = 0;     // current pointer within <text>
223        int  p = 0;     // current pointer within <pattern>
224        int  m = 0;     // does it match (0,1,2)
225        for(; p < P.length; t++, p++) {
226          if(t == T.length && P[p] != '*') return 2;
227          switch(P[p]) {
228            case '\\':  // literal match with following character. Fallthrough
229              p++;
230            default:    // match one char
231              if(p == P.length || T[t] != P[p]) return 0;
232              continue;
233            case '?':   // match anything
234              continue;
235            case '*':   // match everything
236              while(++p < P.length && P[p] == '*') continue; // consecutive stars act just like one
237              if(p == P.length) return 1;                    // trailing star matches everything
238              while(t < T.length) {                          // match the rest recursive
239                if((m = match(text.substring(t++), pattern.substring(p))) != 0) return m;
240              }
241              return 2;
242            case '[':   // match char ranges (beware: java uses unicode!)
243              char l = ' '; 
244              int  r = p < P.length - 2 && P[p + 1] == '^' ? 1 : 0;
245              if(r == 1) p++;  // inverted matching ?
246              for(m = 0; ++p < P.length && P[p] != ']'; l = P[p]) {
247                if(P[p] == '-' ? ++p <= P.length && T[t] <= P[p] && T[t] >= l : T[t] == P[p]) m = 1;
248              }
249              if(m == r) return 0;
250              continue;
251          }
252        }
253        return t == T.length ? 1 : 0;
254      }
255    }