1 16 package com.google.gwt.dev.util; 17 18 import com.google.gwt.core.ext.TreeLogger; 19 import com.google.gwt.core.ext.UnableToCompleteException; 20 import com.google.gwt.core.ext.typeinfo.TypeOracle; 21 import com.google.gwt.util.tools.Utility; 22 23 import org.w3c.dom.Attr ; 24 import org.w3c.dom.DOMException ; 25 import org.w3c.dom.Document ; 26 import org.w3c.dom.Element ; 27 import org.w3c.dom.NamedNodeMap ; 28 import org.w3c.dom.Node ; 29 import org.w3c.dom.Text ; 30 31 import java.io.BufferedReader ; 32 import java.io.BufferedWriter ; 33 import java.io.File ; 34 import java.io.FileInputStream ; 35 import java.io.FileNotFoundException ; 36 import java.io.FileOutputStream ; 37 import java.io.FilenameFilter ; 38 import java.io.IOException ; 39 import java.io.InputStream ; 40 import java.io.InputStreamReader ; 41 import java.io.OutputStream ; 42 import java.io.OutputStreamWriter ; 43 import java.io.PrintWriter ; 44 import java.io.RandomAccessFile ; 45 import java.io.Reader ; 46 import java.io.StringWriter ; 47 import java.io.UnsupportedEncodingException ; 48 import java.lang.reflect.Array ; 49 import java.lang.reflect.InvocationTargetException ; 50 import java.lang.reflect.Method ; 51 import java.net.MalformedURLException ; 52 import java.net.URL ; 53 import java.net.URLConnection ; 54 import java.net.URLDecoder ; 55 import java.security.MessageDigest ; 56 import java.security.NoSuchAlgorithmException ; 57 import java.util.Collection ; 58 import java.util.Iterator ; 59 import java.util.jar.JarEntry ; 60 61 66 public final class Util { 67 68 public static String DEFAULT_ENCODING = "UTF-8"; 69 70 public static final File [] EMPTY_ARRAY_FILE = new File [0]; 71 72 public static final String [] EMPTY_ARRAY_STRING = new String [0]; 73 74 public static char[] HEX_CHARS = new char[] { 75 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 76 'E', 'F'}; 77 78 public static void addAll(Collection c, Object [] a) { 79 for (int i = 0; i < a.length; i++) { 80 c.add(a[i]); 81 } 82 } 83 84 public static byte[] append(byte[] xs, byte x) { 85 int n = xs.length; 86 byte[] t = new byte[n + 1]; 87 System.arraycopy(xs, 0, t, 0, n); 88 t[n] = x; 89 return t; 90 } 91 92 public static Object [] append(Object [] xs, Object x) { 93 int n = xs.length; 94 Object [] t = (Object []) Array.newInstance(xs.getClass().getComponentType(), 95 n + 1); 96 System.arraycopy(xs, 0, t, 0, n); 97 t[n] = x; 98 return t; 99 } 100 101 public static Object [] append(Object [] appendToThis, Object [] these) { 102 if (appendToThis == null) { 103 throw new NullPointerException ("attempt to append to a null array"); 104 } 105 106 if (these == null) { 107 throw new NullPointerException ("attempt to append a null array"); 108 } 109 110 Object [] result; 111 int newSize = appendToThis.length + these.length; 112 Class componentType = appendToThis.getClass().getComponentType(); 113 result = (Object []) Array.newInstance(componentType, newSize); 114 System.arraycopy(appendToThis, 0, result, 0, appendToThis.length); 115 System.arraycopy(these, 0, result, appendToThis.length, these.length); 116 return result; 117 } 118 119 125 public static String computeStrongName(byte[] content) { 126 MessageDigest md5; 127 try { 128 md5 = MessageDigest.getInstance("MD5"); 129 } catch (NoSuchAlgorithmException e) { 130 throw new RuntimeException ("Error initializing MD5", e); 131 } 132 133 for (int i = 0; i < content.length; i++) { 134 md5.update(content[i]); 135 } 136 137 byte[] hash = md5.digest(); 138 139 char[] name = new char[2 * hash.length]; 142 int j = 0; 143 for (int i = 0; i < hash.length; i++) { 144 name[j++] = HEX_CHARS[(hash[i] & 0xF0) >> 4]; 145 name[j++] = HEX_CHARS[hash[i] & 0x0F]; 146 } 147 148 return new String (name); 149 } 150 151 public static boolean copy(TreeLogger logger, File in, File out) 152 throws UnableToCompleteException { 153 FileInputStream fis = null; 154 try { 155 if (in.lastModified() > out.lastModified()) { 156 fis = new FileInputStream (in); 157 copy(logger, fis, out); 158 return true; 159 } else { 160 return false; 161 } 162 } catch (FileNotFoundException e) { 163 logger.log(TreeLogger.ERROR, "Unable to open file '" 164 + in.getAbsolutePath() + "'", e); 165 throw new UnableToCompleteException(); 166 } finally { 167 Utility.close(fis); 168 } 169 } 170 171 public static void copy(TreeLogger logger, InputStream is, File out) 172 throws UnableToCompleteException { 173 FileOutputStream fos = null; 174 try { 175 out.getParentFile().mkdirs(); 176 fos = new FileOutputStream (out); 177 copy(logger, is, fos); 178 } catch (FileNotFoundException e) { 179 logger.log(TreeLogger.ERROR, "Unable to create file '" 180 + out.getAbsolutePath() + "'", e); 181 throw new UnableToCompleteException(); 182 } finally { 183 Utility.close(fos); 184 } 185 } 186 187 public static void copy(TreeLogger logger, InputStream is, OutputStream os) 188 throws UnableToCompleteException { 189 try { 190 byte[] buf = new byte[8 * 1024]; 191 int i = 0; 192 while ((i = is.read(buf)) != -1) { 193 os.write(buf, 0, i); 194 } 195 } catch (IOException e) { 196 logger.log(TreeLogger.ERROR, "Error during copy", e); 197 throw new UnableToCompleteException(); 198 } 199 } 200 201 public static boolean copy(TreeLogger logger, URL in, File out) 202 throws UnableToCompleteException { 203 InputStream is = null; 204 try { 205 URLConnection conn = in.openConnection(); 206 if (conn.getLastModified() > out.lastModified()) { 207 is = in.openStream(); 208 copy(logger, is, out); 209 return true; 210 } else { 211 return false; 212 } 213 } catch (IOException e) { 214 logger.log(TreeLogger.ERROR, "Unable to open '" + in.toExternalForm() 215 + "'", e); 216 throw new UnableToCompleteException(); 217 } finally { 218 Utility.close(is); 219 } 220 } 221 222 public static Reader createReader(TreeLogger logger, URL url) 223 throws UnableToCompleteException { 224 try { 225 return new InputStreamReader (url.openStream()); 226 } catch (IOException e) { 227 logger.log(TreeLogger.ERROR, "Unable to open resource: " + url, e); 228 throw new UnableToCompleteException(); 229 } 230 } 231 232 public static void deleteFilesInDirectory(File dir) { 233 File [] files = dir.listFiles(); 234 if (files != null) { 235 for (int i = 0; i < files.length; i++) { 236 File file = files[i]; 237 if (file.isFile()) { 238 file.delete(); 239 } 240 } 241 } 242 } 243 244 247 public static void deleteFilesStartingWith(File dir, final String prefix) { 248 File [] toDelete = dir.listFiles(new FilenameFilter () { 249 public boolean accept(File dir, String name) { 250 return name.startsWith(prefix); 251 } 252 }); 253 254 if (toDelete != null) { 255 for (int i = 0; i < toDelete.length; i++) { 256 toDelete[i].delete(); 257 } 258 } 259 } 260 261 268 public static String findFileName(String location) { 269 String newLocation = location; 270 if ((location.startsWith("zip:file:")) 271 || (location.startsWith("jar:file:"))) { 272 int lastIndexOfExclam = newLocation.lastIndexOf('!'); 273 if (lastIndexOfExclam != -1) { 276 newLocation = newLocation.substring(0, lastIndexOfExclam); 277 } 278 newLocation = newLocation.substring(9); 279 if (!new File (newLocation).exists()) { 282 try { 283 newLocation = URLDecoder.decode(newLocation, DEFAULT_ENCODING); 284 } catch (UnsupportedEncodingException e) { 285 return location; 287 } 288 } 289 } 290 return newLocation; 291 } 292 293 public static URL findSourceInClassPath(ClassLoader cl, String sourceTypeName) { 294 String toTry = sourceTypeName.replace('.', '/') + ".java"; 295 URL foundURL = cl.getResource(toTry); 296 if (foundURL != null) { 297 return foundURL; 298 } 299 int i = sourceTypeName.lastIndexOf('.'); 300 if (i != -1) { 301 return findSourceInClassPath(cl, sourceTypeName.substring(0, i)); 302 } else { 303 return null; 304 } 305 } 306 307 311 public static String getClassName(Class cls) { 312 return getClassName(cls.getName()); 313 } 314 315 319 public static String getClassName(String className) { 320 return className.substring(className.lastIndexOf('.') + 1); 321 } 322 323 329 public static String getFileFromInstallPath(String relativePath) { 330 String installPath = Utility.getInstallPath(); 331 File file = new File (installPath + '/' + relativePath); 332 return readFileAsString(file); 333 } 334 335 338 public static void hex4(char c, StringBuffer sb) { 339 sb.append(HEX_CHARS[(c & 0xF000) >> 12]); 340 sb.append(HEX_CHARS[(c & 0x0F00) >> 8]); 341 sb.append(HEX_CHARS[(c & 0x00F0) >> 4]); 342 sb.append(HEX_CHARS[c & 0x000F]); 343 } 344 345 354 public static void invokeInaccessableMethod(Class targetClass, 355 String methodName, Class [] argumentTypes, TypeOracle target, 356 Object [] arguments) { 357 String failedReflectErrMsg = "The definition of " + targetClass.getName() 358 + "." + methodName + " has changed in an " + "incompatible way."; 359 try { 360 Method m = targetClass.getDeclaredMethod(methodName, argumentTypes); 361 m.setAccessible(true); 362 m.invoke(target, arguments); 363 } catch (NoSuchMethodException e) { 364 throw new RuntimeException (failedReflectErrMsg, e); 365 } catch (IllegalArgumentException e) { 366 throw new RuntimeException (failedReflectErrMsg, e); 367 } catch (IllegalAccessException e) { 368 throw new RuntimeException (failedReflectErrMsg, e); 369 } catch (InvocationTargetException e) { 370 throw new RuntimeException (failedReflectErrMsg, e); 371 } 372 } 373 374 public static boolean isCompilationUnitOnDisk(String loc) { 375 try { 376 if (new File (loc).exists()) { 377 return true; 378 } 379 380 URL url = new URL (loc); 381 String s = url.toExternalForm(); 382 if (s.startsWith("file:") || s.startsWith("jar:")) { 383 return true; 384 } 385 } catch (MalformedURLException e) { 386 } 388 return false; 389 } 390 391 public static boolean isValidJavaIdent(String token) { 392 if (token.length() == 0) { 393 return false; 394 } 395 396 if (!Character.isJavaIdentifierStart(token.charAt(0))) { 397 return false; 398 } 399 400 for (int i = 1, n = token.length(); i < n; i++) { 401 if (!Character.isJavaIdentifierPart(token.charAt(i))) { 402 return false; 403 } 404 } 405 406 return true; 407 } 408 409 public static void logMissingTypeErrorWithHints(TreeLogger logger, 410 String missingType) { 411 logger = logger.branch(TreeLogger.ERROR, "Unable to find type '" 412 + missingType + "'", null); 413 414 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 415 416 URL sourceURL = findSourceInClassPath(cl, missingType); 417 if (sourceURL != null) { 418 if (missingType.indexOf(".client.") != -1) { 419 Messages.HINT_PRIOR_COMPILER_ERRORS.log(logger, null); 420 Messages.HINT_CHECK_MODULE_INHERITANCE.log(logger, null); 421 } else { 422 if (findSourceInClassPath(cl, missingType) == null) { 425 Messages.HINT_CHECK_MODULE_NONCLIENT_SOURCE_DECL.log(logger, null); 426 } else { 427 Messages.HINT_PRIOR_COMPILER_ERRORS.log(logger, null); 428 } 429 } 430 } else if (!missingType.equals("java.lang.Object")) { 431 Messages.HINT_CHECK_TYPENAME.log(logger, missingType, null); 432 Messages.HINT_CHECK_CLASSPATH_SOURCE_ENTRIES.log(logger, null); 433 } 434 435 if (missingType.indexOf("java.lang.") == 0) { 438 Messages.HINT_CHECK_INHERIT_CORE.log(logger, null); 439 } else if (missingType.indexOf("com.google.gwt.core.") == 0) { 440 Messages.HINT_CHECK_INHERIT_CORE.log(logger, null); 441 } else if (missingType.indexOf("com.google.gwt.user.") == 0) { 442 Messages.HINT_CHECK_INHERIT_USER.log(logger, null); 443 } 444 } 445 446 462 470 public static File makeRelativeFile(File from, File to) { 471 472 String toPath = tryMakeCanonical(to).getAbsolutePath(); 476 File currentFrom = tryMakeCanonical(from.isDirectory() ? from 477 : from.getParentFile()); 478 479 int numberOfBackups = 0; 480 while (currentFrom != null) { 481 String currentFromPath = currentFrom.getPath(); 482 if (toPath.startsWith(currentFromPath)) { 483 break; 486 } else { 487 ++numberOfBackups; 488 currentFrom = currentFrom.getParentFile(); 489 } 490 } 491 492 if (currentFrom == null) { 493 return null; 496 } 497 498 String trailingToPath = toPath.substring(currentFrom.getAbsolutePath().length()); 501 if (currentFrom.getParentFile() != null && trailingToPath.length() > 0) { 502 trailingToPath = trailingToPath.substring(1); 503 } 504 505 File relativeFile = new File (trailingToPath); 506 for (int i = 0; i < numberOfBackups; ++i) { 507 relativeFile = new File ("..", relativeFile.getPath()); 508 } 509 510 return relativeFile; 511 } 512 513 public static String makeRelativePath(File from, File to) { 514 File f = makeRelativeFile(from, to); 515 return (f != null ? f.getPath() : null); 516 } 517 518 public static String makeRelativePath(File from, String to) { 519 File f = makeRelativeFile(from, new File (to)); 520 return (f != null ? f.getPath() : null); 521 } 522 523 526 public static String maybeDumpSource(TreeLogger logger, String location, 527 char[] source, String optionalTypeName) { 528 529 if (isCompilationUnitOnDisk(location)) { 530 return null; 533 } 534 535 File tmpSrc; 536 Throwable caught = null; 537 try { 538 String prefix = "gen"; 539 if (optionalTypeName != null) { 540 prefix = optionalTypeName; 541 } 542 tmpSrc = File.createTempFile(prefix, ".java"); 543 writeCharsAsFile(logger, tmpSrc, source); 544 String dumpPath = tmpSrc.getAbsolutePath(); 545 logger.log(TreeLogger.ERROR, "Compilation problem due to '" + location 546 + "'; see snapshot " + dumpPath, null); 547 return dumpPath; 548 } catch (IOException e) { 549 caught = e; 550 } catch (UnableToCompleteException e) { 551 caught = e; 552 } 553 logger.log(TreeLogger.ERROR, 554 "Compilation problem due to in-memory source '" + location 555 + "', but unable to dump to disk", caught); 556 return null; 557 } 558 559 public static byte[] readFileAsBytes(File file) { 560 FileInputStream fileInputStream = null; 561 try { 562 fileInputStream = new FileInputStream (file); 563 int length = (int) file.length(); 564 byte[] data = new byte[length]; 565 fileInputStream.read(data); 566 return data; 567 } catch (IOException e) { 568 return null; 569 } finally { 570 Utility.close(fileInputStream); 571 } 572 } 573 574 public static char[] readFileAsChars(File file) { 575 if (!file.exists()) { 576 return null; 577 } 578 Reader fileReader = null; 579 try { 580 fileReader = new InputStreamReader (new FileInputStream (file), 581 DEFAULT_ENCODING); 582 int length = (int) file.length(); 583 char[] data = new char[length]; 584 if (length < 0) { 585 return null; 586 } 587 char[] fileContents = new char[length]; 588 int charsRead = fileReader.read(fileContents); 589 if (charsRead < fileContents.length) { 590 595 char[] trimmed = new char[charsRead]; 596 System.arraycopy(fileContents, 0, trimmed, 0, charsRead); 597 fileContents = trimmed; 598 } 599 return fileContents; 600 } catch (IOException e) { 601 return null; 602 } finally { 603 Utility.close(fileReader); 604 } 605 } 606 607 public static String readFileAsString(File file) { 608 try { 609 URL toURL = file.toURL(); 610 char[] buf = readURLAsChars(toURL); 611 if (buf == null) { 612 return null; 613 } 614 return String.valueOf(buf); 615 } catch (MalformedURLException e) { 616 return null; 617 } 618 } 619 620 626 public static String readNextLine(BufferedReader br) { 627 try { 628 String line = br.readLine(); 629 while (line != null) { 630 line = line.trim(); 631 if (line.length() > 0) { 632 break; 633 } 634 line = br.readLine(); 635 } 636 return line; 637 } catch (IOException e) { 638 return null; 639 } 640 } 641 642 645 public static char[] readURLAsChars(URL url) { 646 InputStreamReader reader = null; 648 try { 649 URLConnection connection = url.openConnection(); 650 connection.setUseCaches(false); 651 reader = new InputStreamReader (connection.getInputStream(), 652 DEFAULT_ENCODING); 653 int contentLength = connection.getContentLength(); 654 if (contentLength < 0) { 655 return null; 656 } 657 char[] fileContents = new char[contentLength]; 658 int charsRead = reader.read(fileContents); 659 if (charsRead < fileContents.length) { 660 665 char[] trimmed = new char[charsRead]; 666 System.arraycopy(fileContents, 0, trimmed, 0, charsRead); 667 fileContents = trimmed; 668 } 669 return fileContents; 670 } catch (IOException e) { 671 return null; 672 } finally { 673 Utility.close(reader); 674 } 675 } 676 677 688 public static void recursiveDelete(File file, boolean childrenOnly) { 689 if (file.isDirectory()) { 690 File [] children = file.listFiles(); 691 if (children != null) { 692 for (int i = 0; i < children.length; i++) { 693 recursiveDelete(children[i], false); 694 } 695 } 696 if (childrenOnly) { 697 return; 700 } 701 } 702 file.delete(); 703 } 704 705 public static File removeExtension(File file) { 706 String name = file.getName(); 707 int lastDot = name.lastIndexOf('.'); 708 if (lastDot != -1) { 709 name = name.substring(0, lastDot); 710 } 711 return new File (file.getParentFile(), name); 712 } 713 714 public static Object [] removeNulls(Object [] a) { 715 int n = a.length; 716 for (int i = 0; i < a.length; i++) { 717 if (a[i] == null) { 718 --n; 719 } 720 } 721 722 Class componentType = a.getClass().getComponentType(); 723 Object [] t = (Object []) Array.newInstance(componentType, n); 724 int out = 0; 725 for (int in = 0; in < t.length; in++) { 726 if (a[in] != null) { 727 t[out++] = a[in]; 728 } 729 } 730 return t; 731 } 732 733 737 public static String slashify(String path) { 738 path = path.replace(File.separatorChar, '/'); 739 if (path.endsWith("/")) { 740 path = path.substring(0, path.length() - 1); 741 } 742 return path; 743 } 744 745 750 public static Object [] toArray(Class componentType, Collection coll) { 751 int n = coll.size(); 752 Object [] a = (Object []) Array.newInstance(componentType, n); 753 return coll.toArray(a); 754 } 755 756 760 public static Object [] toArrayReversed(Class componentType, Collection coll) { 761 int n = coll.size(); 762 Object [] a = (Object []) Array.newInstance(componentType, n); 763 int i = n - 1; 764 for (Iterator iter = coll.iterator(); iter.hasNext(); --i) { 765 a[i] = iter.next(); 766 } 767 return a; 768 } 769 770 773 public static String [] toStringArray(Collection coll) { 774 return (String []) toArray(String .class, coll); 775 } 776 777 public static URL toURL(File f) { 778 try { 779 return f.toURI().toURL(); 780 } catch (MalformedURLException e) { 781 throw new RuntimeException ("Failed to convert a File to a URL", e); 782 } 783 } 784 785 public static URL toURL(URL jarUrl, JarEntry jarEntry) { 786 return toURL(jarUrl, jarEntry.toString()); 787 } 788 789 public static URL toURL(URL jarUrl, String path) { 790 try { 791 return new URL ("jar" + ":" + jarUrl.toString() + "!/" + path); 792 } catch (MalformedURLException e) { 793 throw new RuntimeException ("Failed to convert a jar path to a URL", e); 794 } 795 } 796 797 public static String toXml(Document doc) { 798 Throwable caught = null; 799 try { 800 byte[] bytes = toXmlUtf8(doc); 801 return new String (bytes, DEFAULT_ENCODING); 802 } catch (UnsupportedEncodingException e) { 803 caught = e; 804 } 805 throw new RuntimeException ("Unable to encode xml string as utf-8", caught); 806 } 807 808 public static byte[] toXmlUtf8(Document doc) { 809 Throwable caught = null; 810 try { 811 StringWriter sw = new StringWriter (); 812 PrintWriter pw = new PrintWriter (sw); 813 writeDocument(pw, doc); 814 return sw.toString().getBytes(DEFAULT_ENCODING); 815 } catch (UnsupportedEncodingException e) { 816 caught = e; 817 } catch (IOException e) { 818 caught = e; 819 } 820 throw new RuntimeException ( 821 "Unable to encode xml document object as a string", caught); 822 823 828 } 853 854 public static File tryCombine(File parentMaybeIgnored, File childMaybeAbsolute) { 855 if (childMaybeAbsolute == null) { 856 return parentMaybeIgnored; 857 } else if (childMaybeAbsolute.isAbsolute()) { 858 return childMaybeAbsolute; 859 } else { 860 return new File (parentMaybeIgnored, childMaybeAbsolute.getPath()); 861 } 862 } 863 864 public static File tryCombine(File parentMaybeIgnored, 865 String childMaybeAbsolute) { 866 return tryCombine(parentMaybeIgnored, new File (childMaybeAbsolute)); 867 } 868 869 875 public static File tryMakeCanonical(File file) { 876 try { 877 return file.getCanonicalFile(); 878 } catch (IOException e) { 879 return file; 880 } 881 } 882 883 public static void writeBytesToFile(TreeLogger logger, File where, byte[] what) 884 throws UnableToCompleteException { 885 writeBytesToFile(logger, where, new byte[][] {what}); 886 } 887 888 891 public static void writeBytesToFile(TreeLogger logger, File where, 892 byte[][] what) throws UnableToCompleteException { 893 RandomAccessFile f = null; 894 Throwable caught; 895 try { 896 where.getParentFile().mkdirs(); 897 f = new RandomAccessFile (where, "rwd"); 898 long newLen = 0; 899 for (int i = 0; i < what.length; i++) { 900 newLen += what[i].length; 901 f.write(what[i]); 902 } 903 f.setLength(newLen); 904 return; 905 } catch (FileNotFoundException e) { 906 caught = e; 907 } catch (IOException e) { 908 caught = e; 909 } finally { 910 Utility.close(f); 911 } 912 String msg = "Unable to write file '" + where + "'"; 913 logger.log(TreeLogger.ERROR, msg, caught); 914 throw new UnableToCompleteException(); 915 } 916 917 public static void writeCharsAsFile(TreeLogger logger, File file, char[] chars) 918 throws UnableToCompleteException { 919 FileOutputStream stream = null; 920 OutputStreamWriter writer = null; 921 BufferedWriter buffered = null; 922 try { 923 file.getParentFile().mkdirs(); 924 stream = new FileOutputStream (file); 925 writer = new OutputStreamWriter (stream, DEFAULT_ENCODING); 926 buffered = new BufferedWriter (writer); 927 buffered.write(chars); 928 } catch (IOException e) { 929 logger.log(TreeLogger.ERROR, "Unable to write file: " 930 + file.getAbsolutePath(), e); 931 throw new UnableToCompleteException(); 932 } finally { 933 Utility.close(buffered); 934 Utility.close(writer); 935 Utility.close(stream); 936 } 937 } 938 939 public static boolean writeStringAsFile(File file, String string) { 940 FileOutputStream stream = null; 941 OutputStreamWriter writer = null; 942 BufferedWriter buffered = null; 943 try { 944 stream = new FileOutputStream (file); 945 writer = new OutputStreamWriter (stream, DEFAULT_ENCODING); 946 buffered = new BufferedWriter (writer); 947 file.getParentFile().mkdirs(); 948 buffered.write(string); 949 } catch (IOException e) { 950 return false; 951 } finally { 952 Utility.close(buffered); 953 Utility.close(writer); 954 Utility.close(stream); 955 } 956 return true; 957 } 958 959 962 private static String escapeXml(String unescaped) { 963 String escaped = unescaped.replaceAll("\\&", "&"); 964 escaped = escaped.replaceAll("\\<", "<"); 965 escaped = escaped.replaceAll("\\>", ">"); 966 escaped = escaped.replaceAll("\\\"", """); 967 escaped = escaped.replaceAll("\\'", "'"); 968 return escaped; 969 } 970 971 private static void writeAttribute(PrintWriter w, Attr attr, int depth) 972 throws IOException { 973 w.write(attr.getName()); 974 w.write('='); 975 Node c = attr.getFirstChild(); 976 while (c != null) { 977 w.write('"'); 978 writeNode(w, c, depth); 979 w.write('"'); 980 c = c.getNextSibling(); 981 } 982 } 983 984 private static void writeDocument(PrintWriter w, Document d) 985 throws IOException { 986 w.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 987 Node c = d.getFirstChild(); 988 while (c != null) { 989 writeNode(w, c, 0); 990 c = c.getNextSibling(); 991 } 992 } 993 994 private static void writeElement(PrintWriter w, Element el, int depth) 995 throws IOException { 996 String tagName = el.getTagName(); 997 998 writeIndent(w, depth); 999 w.write('<'); 1000 w.write(tagName); 1001 NamedNodeMap attrs = el.getAttributes(); 1002 for (int i = 0, n = attrs.getLength(); i < n; ++i) { 1003 w.write(' '); 1004 writeNode(w, attrs.item(i), depth); 1005 } 1006 1007 Node c = el.getFirstChild(); 1008 if (c != null) { 1009 w.println('>'); 1012 1013 while (c != null) { 1016 writeNode(w, c, depth + 1); 1017 w.println(); 1018 c = c.getNextSibling(); 1019 } 1020 1021 writeIndent(w, depth); 1024 w.write("</"); 1025 w.write(tagName); 1026 w.print('>'); 1027 } else { 1028 w.print("/>"); 1031 } 1032 } 1033 1034 private static void writeIndent(PrintWriter w, int depth) { 1035 for (int i = 0; i < depth; ++i) { 1036 w.write('\t'); 1037 } 1038 } 1039 1040 private static void writeNode(PrintWriter w, Node node, int depth) 1041 throws IOException { 1042 short nodeType = node.getNodeType(); 1043 switch (nodeType) { 1044 case Node.ELEMENT_NODE: 1045 writeElement(w, (Element ) node, depth); 1046 break; 1047 case Node.ATTRIBUTE_NODE: 1048 writeAttribute(w, (Attr ) node, depth); 1049 break; 1050 case Node.DOCUMENT_NODE: 1051 writeDocument(w, (Document ) node); 1052 break; 1053 case Node.TEXT_NODE: 1054 writeText(w, (Text ) node); 1055 break; 1056 1057 case Node.COMMENT_NODE: 1058 case Node.CDATA_SECTION_NODE: 1059 case Node.ENTITY_REFERENCE_NODE: 1060 case Node.ENTITY_NODE: 1061 case Node.PROCESSING_INSTRUCTION_NODE: 1062 default: 1063 throw new RuntimeException ("Unsupported DOM node type: " + nodeType); 1064 } 1065 } 1066 1067 private static void writeText(PrintWriter w, Text text) throws DOMException { 1068 String nodeValue = text.getNodeValue(); 1069 String escaped = escapeXml(nodeValue); 1070 w.write(escaped); 1071 } 1072 1073 1076 private Util() { 1077 } 1078 1079} 1080 | Popular Tags |