View Javadoc

1   /*
2    * Created on 24-oct.-2004 */
3   package DTDDoc;
4   
5   import java.io.File;
6   import java.io.FileInputStream;
7   import java.io.FileNotFoundException;
8   import java.io.FileOutputStream;
9   import java.io.IOException;
10  import java.io.InputStream;
11  import java.io.OutputStream;
12  import java.util.ArrayList;
13  import java.util.Arrays;
14  import java.util.Collection;
15  import java.util.Collections;
16  import java.util.Comparator;
17  import java.util.Enumeration;
18  import java.util.LinkedList;
19  import java.util.List;
20  import java.util.StringTokenizer;
21  
22  
23  /** A class that gather some useful tools.
24   *
25   * @author expertmb (http://www.experts-exchange.com/M_237837.html)
26   * @author stefan schampailler_at_skynet_dot_be */
27  
28  
29  public class Tools {
30  
31      /** Copy the whole content of a stream into another.
32       *
33       * @param source Input stream.
34       * @param destination Output stream.
35       * @throws IOException If anything goes wrong.
36       */
37  
38      private static void streamCopy( InputStream source, OutputStream destination)
39          throws IOException {
40  
41          if( source == null)
42              throw new IOException( "Trying to input from a null stream");
43          else if( destination == null)
44              throw new IOException( "Trying to output to a null stream");
45  
46          byte[] buffer = new byte[16384];
47  
48          while (true) {
49              int bytes_read = source.read(buffer);
50              if (bytes_read > 0)
51                  destination.write(buffer, 0, bytes_read);
52              else
53                  break;
54          }
55      }
56  
57      /** Copy the content of stream into another and close both of them when
58       * done.
59       *
60       * @param source Source stream.
61       * @param destination Destination stream.
62       * @throws IOException If anything goes wrong.
63       */
64  
65      private static void streamCopyAndClose( InputStream source,
66              OutputStream destination) throws IOException {
67  
68          IOException exception = null;
69  
70          try {
71              streamCopy( source, destination);
72          } catch( IOException ex) {
73              exception = ex;
74          }
75  
76          if (source != null)
77              try {
78                  source.close();
79              } catch (IOException e) {
80                  if( exception != null)
81                      exception = new IOException( exception.getMessage()+" (and I was not able to close this stream)");
82              }
83  
84          if (destination != null)
85              try {
86                  destination.close();
87              } catch (IOException e) {
88                  if( exception != null)
89                      exception = new IOException( exception.getMessage()+" (and I was not able to close this stream)");
90              }
91  
92          if( exception != null)
93              throw exception;
94      }
95  
96      /** Open a file so that it's ready to be written in. This takes as
97       * much care as possible to ensure the operation is possible.
98       *
99       * @param destinationFile File to open.
100      * @return A stream to write (overwrite) into the file.
101      * @throws FileCopyException
102      */
103     private static OutputStream openToWrite( File destinationFile) throws FileCopyException {
104 
105         // If the destination exists, make sure it is a writeable file
106         // and ask before overwriting it.  If the destination doesn't
107         // exist, make sure the directory exists and is writeable.
108         if (destinationFile.exists()) {
109             if (destinationFile.isFile()) {
110                 if (!destinationFile.canWrite())
111                     throw new FileCopyException("Can't write into "
112                             + destinationFile);
113                 /*
114                  System.out.print("File " + dest_name
115                  + " already exists.  Overwrite? (Y/N): ");
116                  System.out.flush();
117 
118                  DataInputStream in = new DataInputStream(System.in);
119                  String response = in.readLine();
120                  if (!response.equals("Y") && !response.equals("y"))
121                  throw new FileCopyException("FileCopy: copy cancelled."); */
122             } else
123                 throw new FileCopyException(destinationFile + " is not a file.");
124         } else {
125             File parentdir = parent(destinationFile);
126             if (!parentdir.exists())
127                 throw new FileCopyException( "Destination directory " +
128                         "doesn't exist for " + destinationFile);
129             if (!parentdir.canWrite())
130                 throw new FileCopyException( "Destination directory " +
131                         "for " + destinationFile + " is unwritable.");
132         }
133 
134         // If we've gotten this far, then everything is okay; we can
135         // copy the file.
136 
137         try {
138             return new FileOutputStream(destinationFile);
139         } catch( FileNotFoundException ex) {
140             throw new FileCopyException("Can't write to "+destinationFile+
141                     " because "+ex.getLocalizedMessage());
142         }
143     }
144 
145     /** Copies a resource file (in-jar) to a given destination.
146      *
147      * @param name Full path to the resource (relative to the jar though).
148      * @param destinationFile Where to copy the file.
149      * @throws FileCopyException
150      */
151 
152     public static void copyFromResource( String name, File destinationFile)
153         throws FileCopyException {
154 
155         //System.out.println("Copying "+name);
156 
157         InputStream source = Tools.class.getResourceAsStream( name);
158 
159         if( source == null) {
160             String error = "Unable to find "+name+".";
161             if( !name.startsWith("/"))
162                 error += " Please note that name doesn't start with a slash '/'.";
163 
164             throw new FileCopyException( error);
165         }
166 
167         OutputStream destination = openToWrite( destinationFile);
168 
169         try {
170             streamCopyAndClose( source, destination);
171         } catch( IOException ex) {
172             throw new FileCopyException("Unable to copy "+name+" into "+destinationFile);
173         }
174     }
175 
176     /** Copy one file into antoher. If the destination file already exists, it
177      * is overwritten.
178      *
179      * @param sourceFile Source path.
180      * @param destinationFile Destination path.
181      * @throws IOException
182      */
183 
184     public static void copy( File sourceFile, File destinationFile)
185         throws IOException {
186 
187         // First make sure the specified source file
188         // exists, is a file, and is readable.
189         if (!sourceFile.exists() || !sourceFile.isFile())
190             throw new FileCopyException(
191                     "Can't find "+sourceFile);
192 
193         if (!sourceFile.canRead())
194             throw new FileCopyException("File " + sourceFile +
195             " is unreadable");
196 
197         InputStream source = new FileInputStream( sourceFile);
198         OutputStream destination = openToWrite( destinationFile);
199 
200         try {
201             streamCopyAndClose( source, destination);
202         } catch( IOException ex) {
203             throw new FileCopyException("Unable to copy "+sourceFile+" into "+destinationFile);
204         }
205     }
206 
207 
208     /** Get the parent of a given path.
209      *
210      * @param f The path.
211      * @return The path's parent. Null if there's no such parent.
212      */
213 
214     public static File parent(File f) {
215             String dirname = f.getParent();
216             if (dirname == null) {
217                 if (f.isAbsolute())
218                     return new File(File.separator);
219                 else
220                     return new File(System.getProperty("user.dir"));
221             }
222             return new File(dirname);
223         }
224 
225     /** Returns a sorted copy of a given collection.
226      *
227      * @param collection Colelction to sort.
228      * @param comparator Comparator to use while sorting.
229      * @return A sorted copy of the collection.
230      */
231 
232     static public Collection sort( Collection collection, Comparator comparator) {
233         List l = new ArrayList( collection);
234         Collections.sort( l, comparator);
235         return l;
236     }
237 
238     /** Transform a list into an array. The list is a string of texts
239      *  separated by a character called "separator".
240      *  @param s The list
241      *  @param separator the separator.
242      *  @return An array containing all the elements of the list. Null
243      *      if the list is empty. */
244 
245     public static String[] listToArray( String s, String separator) {
246         if( s == null) return null;
247 
248         List l = new ArrayList();
249         StringTokenizer st = new StringTokenizer( s, separator, false);
250 
251         while( st.hasMoreTokens()) {
252             l.add( st.nextToken());
253         }
254 
255         if( l.size() <= 0) return null;
256 
257         return (String[])l.toArray(new String[l.size()]);
258 
259     }
260 
261 
262     public static String join( String[] array, String separator) {
263         int len = array.length;
264         StringBuffer buff = new StringBuffer();
265         for (int i = 0; i < len; i++) {
266             if (i > 0) {
267                 buff.append(separator);
268             }
269             buff.append(array[i]);
270         }
271         return buff.toString();
272     }
273 
274     /** Escape all non-ASCII character in a UNICODE string.
275      * The "escaping convention" is the one of HTML : &amp;#xxxx;.
276      *
277      * <p>Additionally, this function can escape the single quote character for
278      * Javascript strings.</p>
279      *
280      *
281      * @param s String to escape. If null, nothing is done.
282      * @param javascript If true, escapes the single quote character into
283      *     \' so that it can appear in a single quote delimited Javascript
284      *     string.
285      * @return The escaped version of the string. If the parameter is null,
286      *     returns null.
287      */
288 
289     public static String escapeHTMLUnicode( String s, boolean javascript) {
290 
291         // MJK 8/26/2004 Made this public static so it can be used from
292         // ElementTreeBuilder.
293         // SC 20/10/2004 Merged the javascript capability for the
294         // ElementTreeBuidler as well
295 
296         if( s != null) {
297 
298             StringBuffer out = new StringBuffer(s.length()*2);
299 
300             for (int j = 0; j < s.length(); j++) {
301                 char c = s.charAt(j);
302 
303                 if (javascript && c == '\'')
304                     out.append( "\\'");
305                 else if( (int) c < 128) // ASCII char ?
306                     // Yes, leave it unchanged
307                     out.append( c);
308                 else
309                     // No, escape it to preserve encoding
310                     out.append("&#").append((int) c).append(';');
311             }
312 
313             return out.toString();
314 
315         } else
316             return null;
317     }
318 
319     public static List enumerationToList( Enumeration enumeration) {
320 
321         if( enumeration == null)
322             return null;
323 
324         List c = new LinkedList();
325 
326         while( enumeration.hasMoreElements())
327             c.add( enumeration.nextElement());
328 
329         return c;
330     }
331 
332     /** Extract the file name out of a full path. For example,
333      *  for "/alpha/bravo/zulu", this function will return "zulu".
334      *
335      *  @param path The full path.
336      *  @return The file name part of the path. */
337 
338     public static String getFilename(String path) {
339 
340         // Warning ! lastIndexOf can return -1 !!!
341         int li = path.lastIndexOf(File.separator) + 1;
342 
343         return path.substring(li);
344     }
345 
346     /** Will create the directories present in the path of a file.
347      *  @param f The file to get the path from. */
348 
349     public static void makeFileDir(File f) throws IOException {
350         // FIXME Move this in a supporting class
351         String c = f.getCanonicalPath();
352         File dir = new File(c.substring(0, c.lastIndexOf(File.separator)));
353         dir.mkdirs();
354     }
355 
356     /*
357     public static File createBackup( File source) throws IOException {
358         File backup = File.createTempFile( "PFBackup_", ".back",
359                 parent( source));
360 
361         copy( source, backup);
362         return backup;
363     } */
364 
365 
366     public final static List HTML_TAGS;
367     static {
368         List html = Arrays.asList(new String[] {
369             "script", "noscript", "iframe", "div", "p",
370             "h1", "h2", "h3", "h4", "h5", "h6", "ul", "ol",
371             "menu", "dir", "li", "dl", "dt", "dd", "address", "hr",
372             "pre", "blockquote", "center", "ins", "del", "a", "span",
373             "bdo", "br", "em", "strong", "dfn", "code", "samp", "kbd", "var", "cite",
374             "abbr", "acronym", "q", "sub", "sup", "tt", "i", "b", "big", "small",
375             "u", "s", "strike", "basefont", "font", "object", "param", "applet",
376             "img", "map", "area", "form", "label", "input", "select", "optgroup",
377             "option", "textarea", "fieldset", "legend", "button", "isindex",
378             "table", "caption", "thead", "tfoot", "tbody", "colgroup", "col",
379             "tr", "th", "td"
380         });
381         Collections.sort(html);
382         HTML_TAGS = Collections.unmodifiableList(html);
383     }
384 
385     public static boolean startsWithHtmlTag(String txt) {
386         // an HTML tag starts with either < or </
387         if (txt.startsWith("</")) {
388             txt = txt.substring(2);
389         } else if (txt.startsWith("<")) {
390             txt = txt.substring(1);
391         } else {
392             return false;
393         }
394 
395         // the tag name ends at the first space or >
396         int idx = txt.indexOf(' ');
397         if (idx > 0) {
398             txt = txt.substring(0, idx);
399         }
400         idx = txt.indexOf('>');
401         if (idx > 0) {
402             txt = txt.substring(0, idx);
403         }
404 
405         String tag = txt.toLowerCase();
406         return (Collections.binarySearch(HTML_TAGS, tag) >= 0);
407     }
408 
409     public static String replace(String src, String token, String with) {
410         int index = src.indexOf(token);
411         if (index < 0) {
412             return src;
413         }
414         StringBuffer buffer = new StringBuffer();
415         int prev = 0;
416         while (index >= 0) {
417             buffer.append(src.substring(prev, index));
418             buffer.append(with);
419             prev = index + token.length();
420             index = src.indexOf(token, prev);
421         }
422         buffer.append(src.substring(prev));
423         return buffer.toString();
424     }
425 }