1 30 package com.tc.asm.xml; 31 32 import java.io.BufferedOutputStream ; 33 import java.io.ByteArrayInputStream ; 34 import java.io.ByteArrayOutputStream ; 35 import java.io.FileInputStream ; 36 import java.io.FileOutputStream ; 37 import java.io.IOException ; 38 import java.io.InputStream ; 39 import java.io.OutputStream ; 40 import java.io.OutputStreamWriter ; 41 import java.io.Writer ; 42 import java.util.zip.ZipEntry ; 43 import java.util.zip.ZipInputStream ; 44 import java.util.zip.ZipOutputStream ; 45 46 import javax.xml.transform.Source ; 47 import javax.xml.transform.Templates ; 48 import javax.xml.transform.TransformerConfigurationException ; 49 import javax.xml.transform.TransformerException ; 50 import javax.xml.transform.TransformerFactory ; 51 import javax.xml.transform.sax.SAXResult ; 52 import javax.xml.transform.sax.SAXSource ; 53 import javax.xml.transform.sax.SAXTransformerFactory ; 54 import javax.xml.transform.sax.TransformerHandler ; 55 import javax.xml.transform.stream.StreamSource ; 56 57 import com.tc.asm.ClassReader; 58 59 import org.xml.sax.Attributes ; 60 import org.xml.sax.ContentHandler ; 61 import org.xml.sax.InputSource ; 62 import org.xml.sax.SAXException ; 63 import org.xml.sax.XMLReader ; 64 import org.xml.sax.ext.LexicalHandler ; 65 import org.xml.sax.helpers.AttributesImpl ; 66 import org.xml.sax.helpers.DefaultHandler ; 67 import org.xml.sax.helpers.XMLReaderFactory ; 68 69 90 public class Processor { 91 92 public static final int BYTECODE = 1; 93 94 public static final int MULTI_XML = 2; 95 96 public static final int SINGLE_XML = 3; 97 98 private static final String SINGLE_XML_NAME = "classes.xml"; 99 100 private int inRepresentation; 101 102 private int outRepresentation; 103 104 private InputStream input = null; 105 106 private OutputStream output = null; 107 108 private Source xslt = null; 109 110 private boolean computeMax; 111 112 private int n = 0; 113 114 public Processor( 115 int inRepresenation, 116 int outRepresentation, 117 InputStream input, 118 OutputStream output, 119 Source xslt) 120 { 121 this.inRepresentation = inRepresenation; 122 this.outRepresentation = outRepresentation; 123 this.input = input; 124 this.output = output; 125 this.xslt = xslt; 126 this.computeMax = true; 127 } 128 129 public int process() throws TransformerException , IOException , SAXException 130 { 131 ZipInputStream zis = new ZipInputStream (input); 132 final ZipOutputStream zos = new ZipOutputStream (output); 133 final OutputStreamWriter osw = new OutputStreamWriter (zos); 134 135 Thread.currentThread() 136 .setContextClassLoader(getClass().getClassLoader()); 137 138 TransformerFactory tf = TransformerFactory.newInstance(); 139 if (!tf.getFeature(SAXSource.FEATURE) 140 || !tf.getFeature(SAXResult.FEATURE)) 141 return 0; 142 143 SAXTransformerFactory saxtf = (SAXTransformerFactory ) tf; 144 Templates templates = null; 145 if (xslt != null) { 146 templates = saxtf.newTemplates(xslt); 147 } 148 149 152 EntryElement entryElement = getEntryElement(zos); 153 154 ContentHandler outDocHandler = null; 155 switch (outRepresentation) { 156 case BYTECODE: 157 outDocHandler = new OutputSlicingHandler(new ASMContentHandlerFactory(zos, 158 computeMax), 159 entryElement, 160 false); 161 break; 162 163 case MULTI_XML: 164 outDocHandler = new OutputSlicingHandler(new SAXWriterFactory(osw, 165 true), 166 entryElement, 167 true); 168 break; 169 170 case SINGLE_XML: 171 ZipEntry outputEntry = new ZipEntry (SINGLE_XML_NAME); 172 zos.putNextEntry(outputEntry); 173 outDocHandler = new SAXWriter(osw, false); 174 break; 175 176 } 177 178 ContentHandler inDocHandler = null; 181 if (templates == null) { 182 inDocHandler = outDocHandler; 183 } else { 184 inDocHandler = new InputSlicingHandler("class", 185 outDocHandler, 186 new TransformerHandlerFactory(saxtf, 187 templates, 188 outDocHandler)); 189 } 190 ContentHandlerFactory inDocHandlerFactory = new SubdocumentHandlerFactory(inDocHandler); 191 192 if (inDocHandler != null && inRepresentation != SINGLE_XML) { 193 inDocHandler.startDocument(); 194 inDocHandler.startElement("", 195 "classes", 196 "classes", 197 new AttributesImpl ()); 198 } 199 200 int i = 0; 201 ZipEntry ze = null; 202 while ((ze = zis.getNextEntry()) != null) { 203 update(ze.getName(), n++); 204 if (isClassEntry(ze)) { 205 processEntry(zis, ze, inDocHandlerFactory); 206 } else { 207 OutputStream os = entryElement.openEntry(getName(ze)); 208 copyEntry(zis, os); 209 entryElement.closeEntry(); 210 } 211 212 i++; 213 } 214 215 if (inDocHandler != null && inRepresentation != SINGLE_XML) { 216 inDocHandler.endElement("", "classes", "classes"); 217 inDocHandler.endDocument(); 218 } 219 220 if (outRepresentation == SINGLE_XML) { 221 zos.closeEntry(); 222 } 223 zos.flush(); 224 zos.close(); 225 226 return i; 227 } 228 229 private void copyEntry(InputStream is, OutputStream os) throws IOException { 230 if (outRepresentation == SINGLE_XML) 231 return; 232 233 byte[] buff = new byte[2048]; 234 int i; 235 while ((i = is.read(buff)) != -1) { 236 os.write(buff, 0, i); 237 } 238 } 239 240 private boolean isClassEntry(ZipEntry ze) { 241 String name = ze.getName(); 242 return inRepresentation == SINGLE_XML && name.equals(SINGLE_XML_NAME) 243 || name.endsWith(".class") || name.endsWith(".class.xml"); 244 } 245 246 private void processEntry( 247 final ZipInputStream zis, 248 ZipEntry ze, 249 ContentHandlerFactory handlerFactory) 250 { 251 ContentHandler handler = handlerFactory.createContentHandler(); 252 try { 253 254 261 boolean singleInputDocument = inRepresentation == SINGLE_XML; 262 if (inRepresentation == BYTECODE) { ClassReader cr = new ClassReader(readEntry(zis, ze)); 265 cr.accept(new SAXClassAdapter(handler, singleInputDocument), 266 false); 267 268 } else { XMLReader reader = XMLReaderFactory.createXMLReader(); 270 reader.setContentHandler(handler); 271 reader.parse(new InputSource (singleInputDocument 272 ? (InputStream ) new ProtectedInputStream(zis) 273 : new ByteArrayInputStream (readEntry(zis, ze)))); 274 275 } 276 } catch (Exception ex) { 277 update(ze.getName(), 0); 278 update(ex, 0); 279 } 280 } 281 282 private EntryElement getEntryElement(ZipOutputStream zos) { 283 if (outRepresentation == SINGLE_XML) { 284 return new SingleDocElement(zos); 285 } 286 return new ZipEntryElement(zos); 287 } 288 289 319 private String getName(ZipEntry ze) { 320 String name = ze.getName(); 321 if (isClassEntry(ze)) { 322 if (inRepresentation != BYTECODE && outRepresentation == BYTECODE) { 323 name = name.substring(0, name.length() - 4); } else if (inRepresentation == BYTECODE 326 && outRepresentation != BYTECODE) 327 { 328 name = name.concat(".xml"); } 330 } 333 return name; 334 } 335 336 private byte[] readEntry(ZipInputStream zis, ZipEntry ze) 337 throws IOException 338 { 339 long size = ze.getSize(); 340 if (size > -1) { 341 byte[] buff = new byte[(int) size]; 342 int k = 0; 343 int n; 344 while(( n = zis.read(buff, k, buff.length-k)) > 0) { 345 k += n; 346 } 347 return buff; 348 } 349 350 ByteArrayOutputStream bos = new ByteArrayOutputStream (); 351 byte[] buff = new byte[4096]; 352 int i; 353 while ((i = zis.read(buff)) != -1) { 354 bos.write(buff, 0, i); 355 } 356 return bos.toByteArray(); 357 } 358 359 364 protected void update(Object arg, int n) { 365 if (arg instanceof Throwable ) { 366 ((Throwable ) arg).printStackTrace(); 367 } else { 368 if ((n % 100) == 0) { 369 System.err.println(n + " " + arg); 370 } 371 } 372 } 373 374 public static void main(String [] args) throws Exception { 375 if (args.length < 2) { 376 showUsage(); 377 return; 378 } 379 380 int inRepresentation = getRepresentation(args[0]); 381 int outRepresentation = getRepresentation(args[1]); 382 383 InputStream is = System.in; 384 OutputStream os = new BufferedOutputStream (System.out); 385 386 Source xslt = null; 387 389 for (int i = 2; i < args.length; i++) { 390 if ("-in".equals(args[i])) { 391 is = new FileInputStream (args[++i]); 392 393 } else if ("-out".equals(args[i])) { 394 os = new BufferedOutputStream (new FileOutputStream (args[++i])); 395 396 } else if ("-xslt".equals(args[i])) { 397 xslt = new StreamSource (new FileInputStream (args[++i])); 398 399 402 } else { 403 showUsage(); 404 return; 405 406 } 407 } 408 409 if (inRepresentation == 0 || outRepresentation == 0) { 410 showUsage(); 411 return; 412 } 413 414 Processor m = new Processor(inRepresentation, 415 outRepresentation, 416 is, 417 os, 418 xslt); 419 420 long l1 = System.currentTimeMillis(); 421 int n = m.process(); 422 long l2 = System.currentTimeMillis(); 423 System.err.println(n); 424 System.err.println("" + (l2 - l1) + "ms " + (1000f * n / (l2 - l1)) 425 + " resources/sec"); 426 } 427 428 private static int getRepresentation(String s) { 429 if ("code".equals(s)) { 430 return BYTECODE; 431 } else if ("xml".equals(s)) { 432 return MULTI_XML; 433 } else if ("singlexml".equals(s)) { 434 return SINGLE_XML; 435 } 436 return 0; 437 } 438 439 private static void showUsage() { 440 System.err.println("Usage: Main <in format> <out format> [-in <input jar>] [-out <output jar>] [-xslt <xslt file>]"); 441 System.err.println(" when -in or -out is omitted sysin and sysout would be used"); 442 System.err.println(" <in format> and <out format> - code | xml | singlexml"); 443 } 444 445 449 private static final class ProtectedInputStream extends InputStream { 450 private final InputStream is; 451 452 private ProtectedInputStream(InputStream is) { 453 super(); 454 this.is = is; 455 } 456 457 public final void close() throws IOException { 458 } 459 460 public final int read() throws IOException { 461 return is.read(); 462 } 463 464 public final int read(byte[] b, int off, int len) throws IOException { 465 return is.read(b, off, len); 466 } 467 468 public final int available() throws IOException { 469 return is.available(); 470 } 471 } 472 473 478 private static interface ContentHandlerFactory { 479 480 485 ContentHandler createContentHandler(); 486 487 } 488 489 492 private static final class SAXWriterFactory implements 493 ContentHandlerFactory 494 { 495 private Writer w; 496 497 private boolean optimizeEmptyElements; 498 499 public SAXWriterFactory(Writer w, boolean optimizeEmptyElements) { 500 this.w = w; 501 this.optimizeEmptyElements = optimizeEmptyElements; 502 } 503 504 public final ContentHandler createContentHandler() { 505 return new SAXWriter(w, optimizeEmptyElements); 506 } 507 508 } 509 510 513 private static final class ASMContentHandlerFactory implements 514 ContentHandlerFactory 515 { 516 private OutputStream os; 517 518 private boolean computeMax; 519 520 public ASMContentHandlerFactory(OutputStream os, boolean computeMax) { 521 this.os = os; 522 this.computeMax = computeMax; 523 } 524 525 public final ContentHandler createContentHandler() { 526 return new ASMContentHandler(os, computeMax); 527 } 528 529 } 530 531 534 private static final class TransformerHandlerFactory implements 535 ContentHandlerFactory 536 { 537 private SAXTransformerFactory saxtf; 538 539 private Templates templates; 540 541 private ContentHandler outputHandler; 542 543 public TransformerHandlerFactory( 544 SAXTransformerFactory saxtf, 545 Templates templates, 546 ContentHandler outputHandler) 547 { 548 this.saxtf = saxtf; 549 this.templates = templates; 550 this.outputHandler = outputHandler; 551 } 552 553 public final ContentHandler createContentHandler() { 554 try { 555 TransformerHandler handler = saxtf.newTransformerHandler(templates); 556 handler.setResult(new SAXResult (outputHandler)); 557 return handler; 558 } catch (TransformerConfigurationException ex) { 559 throw new RuntimeException (ex.toString()); 560 } 561 } 562 } 563 564 567 private final static class SubdocumentHandlerFactory implements 568 ContentHandlerFactory 569 { 570 private ContentHandler subdocumentHandler; 571 572 public SubdocumentHandlerFactory(ContentHandler subdocumentHandler) { 573 this.subdocumentHandler = subdocumentHandler; 574 } 575 576 public final ContentHandler createContentHandler() { 577 return subdocumentHandler; 578 } 579 580 } 581 582 590 private final static class SAXWriter extends DefaultHandler implements 591 LexicalHandler 592 { 593 private static final char[] OFF = " ".toCharArray(); 594 595 private Writer w; 596 597 private boolean optimizeEmptyElements; 598 599 private boolean openElement = false; 600 601 private int ident = 0; 602 603 610 public SAXWriter(Writer w, boolean optimizeEmptyElements) { 611 this.w = w; 612 this.optimizeEmptyElements = optimizeEmptyElements; 613 } 614 615 public final void startElement( 616 String ns, 617 String localName, 618 String qName, 619 Attributes atts) throws SAXException 620 { 621 try { 622 closeElement(); 623 624 writeIdent(); 625 w.write("<".concat(qName)); 626 if (atts != null && atts.getLength() > 0) 627 writeAttributes(atts); 628 629 if (!optimizeEmptyElements) { 630 w.write(">\n"); 631 } else { 632 openElement = true; 633 } 634 ident += 2; 635 636 } catch (IOException ex) { 637 throw new SAXException (ex); 638 639 } 640 } 641 642 public final void endElement(String ns, String localName, String qName) 643 throws SAXException 644 { 645 ident -= 2; 646 try { 647 if (openElement) { 648 w.write("/>\n"); 649 openElement = false; 650 } else { 651 writeIdent(); 652 w.write("</" + qName + ">\n"); 653 } 654 655 } catch (IOException ex) { 656 throw new SAXException (ex); 657 658 } 659 } 660 661 public final void endDocument() throws SAXException { 662 try { 663 w.flush(); 664 665 } catch (IOException ex) { 666 throw new SAXException (ex); 667 668 } 669 } 670 671 public final void comment(char[] ch, int off, int len) 672 throws SAXException 673 { 674 try { 675 closeElement(); 676 677 writeIdent(); 678 w.write("<!-- "); 679 w.write(ch, off, len); 680 w.write(" -->\n"); 681 682 } catch (IOException ex) { 683 throw new SAXException (ex); 684 685 } 686 } 687 688 public final void startDTD(String arg0, String arg1, String arg2) 689 throws SAXException 690 { 691 } 692 693 public final void endDTD() throws SAXException { 694 } 695 696 public final void startEntity(String arg0) throws SAXException { 697 } 698 699 public final void endEntity(String arg0) throws SAXException { 700 } 701 702 public final void startCDATA() throws SAXException { 703 } 704 705 public final void endCDATA() throws SAXException { 706 } 707 708 private final void writeAttributes(Attributes atts) throws IOException { 709 StringBuffer sb = new StringBuffer (); 710 int len = atts.getLength(); 711 for (int i = 0; i < len; i++) { 712 sb.append(" ") 713 .append(atts.getLocalName(i)) 714 .append("=\"") 715 .append(esc(atts.getValue(i))) 716 .append("\""); 717 } 718 w.write(sb.toString()); 719 } 720 721 727 private final String esc(String str) { 728 StringBuffer sb = new StringBuffer (str.length()); 729 for (int i = 0; i < str.length(); i++) { 730 char ch = str.charAt(i); 731 switch (ch) { 732 case '&': 733 sb.append("&"); 734 break; 735 736 case '<': 737 sb.append("<"); 738 break; 739 740 case '>': 741 sb.append(">"); 742 break; 743 744 case '\"': 745 sb.append("""); 746 break; 747 748 default: 749 if (ch > 0x7f) { 750 sb.append("&#") 751 .append(Integer.toString(ch)) 752 .append(';'); 753 } else { 754 sb.append(ch); 755 } 756 757 } 758 } 759 return sb.toString(); 760 } 761 762 private final void writeIdent() throws IOException { 763 int n = ident; 764 while (n > 0) { 765 if (n > OFF.length) { 766 w.write(OFF); 767 n -= OFF.length; 768 } else { 769 w.write(OFF, 0, n); 770 n = 0; 771 } 772 } 773 } 774 775 private final void closeElement() throws IOException { 776 if (openElement) { 777 w.write(">\n"); 778 } 779 openElement = false; 780 } 781 782 } 783 784 793 private final static class InputSlicingHandler extends DefaultHandler { 794 private String subdocumentRoot; 795 796 private ContentHandler rootHandler; 797 798 private ContentHandlerFactory subdocumentHandlerFactory; 799 800 private boolean subdocument = false; 801 802 private ContentHandler subdocumentHandler; 803 804 817 public InputSlicingHandler( 818 String subdocumentRoot, 819 ContentHandler rootHandler, 820 ContentHandlerFactory subdocumentHandlerFactory) 821 { 822 this.subdocumentRoot = subdocumentRoot; 823 this.rootHandler = rootHandler; 824 this.subdocumentHandlerFactory = subdocumentHandlerFactory; 825 } 826 827 public final void startElement( 828 String namespaceURI, 829 String localName, 830 String qName, 831 Attributes list) throws SAXException 832 { 833 if (subdocument) { 834 subdocumentHandler.startElement(namespaceURI, 835 localName, 836 qName, 837 list); 838 } else if (localName.equals(subdocumentRoot)) { 839 subdocumentHandler = subdocumentHandlerFactory.createContentHandler(); 840 subdocumentHandler.startDocument(); 841 subdocumentHandler.startElement(namespaceURI, 842 localName, 843 qName, 844 list); 845 subdocument = true; 846 } else if (rootHandler != null) { 847 rootHandler.startElement(namespaceURI, localName, qName, list); 848 } 849 } 850 851 public final void endElement( 852 String namespaceURI, 853 String localName, 854 String qName) throws SAXException 855 { 856 if (subdocument) { 857 subdocumentHandler.endElement(namespaceURI, localName, qName); 858 if (localName.equals(subdocumentRoot)) { 859 subdocumentHandler.endDocument(); 860 subdocument = false; 861 } 862 } else if (rootHandler != null) { 863 rootHandler.endElement(namespaceURI, localName, qName); 864 } 865 } 866 867 public final void startDocument() throws SAXException { 868 if (rootHandler != null) { 869 rootHandler.startDocument(); 870 } 871 } 872 873 public final void endDocument() throws SAXException { 874 if (rootHandler != null) { 875 rootHandler.endDocument(); 876 877 } 878 } 879 880 public final void characters(char[] buff, int offset, int size) 881 throws SAXException 882 { 883 if (subdocument) { 884 subdocumentHandler.characters(buff, offset, size); 885 } else if (rootHandler != null) { 886 rootHandler.characters(buff, offset, size); 887 } 888 } 889 890 } 891 892 901 private static final class OutputSlicingHandler extends DefaultHandler { 902 private String subdocumentRoot; 903 904 private ContentHandlerFactory subdocumentHandlerFactory; 905 906 private EntryElement entryElement; 907 908 private boolean isXml; 909 910 private boolean subdocument = false; 911 912 private ContentHandler subdocumentHandler; 913 914 925 public OutputSlicingHandler( 926 ContentHandlerFactory subdocumentHandlerFactory, 927 EntryElement entryElement, 928 boolean isXml) 929 { 930 this.subdocumentRoot = "class"; 931 this.subdocumentHandlerFactory = subdocumentHandlerFactory; 932 this.entryElement = entryElement; 933 this.isXml = isXml; 934 } 935 936 public final void startElement( 937 String namespaceURI, 938 String localName, 939 String qName, 940 Attributes list) throws SAXException 941 { 942 if (subdocument) { 943 subdocumentHandler.startElement(namespaceURI, 944 localName, 945 qName, 946 list); 947 } else if (localName.equals(subdocumentRoot)) { 948 String name = list.getValue("name"); 949 if (name == null || name.length() == 0) 950 throw new SAXException ("Class element without name attribute."); 951 try { 952 entryElement.openEntry(isXml 953 ? name.concat(".class.xml") 954 : name.concat(".class")); 955 } catch (IOException ex) { 956 throw new SAXException (ex.toString(), ex); 957 } 958 subdocumentHandler = subdocumentHandlerFactory.createContentHandler(); 959 subdocumentHandler.startDocument(); 960 subdocumentHandler.startElement(namespaceURI, 961 localName, 962 qName, 963 list); 964 subdocument = true; 965 } 966 } 967 968 public final void endElement( 969 String namespaceURI, 970 String localName, 971 String qName) throws SAXException 972 { 973 if (subdocument) { 974 subdocumentHandler.endElement(namespaceURI, localName, qName); 975 if (localName.equals(subdocumentRoot)) { 976 subdocumentHandler.endDocument(); 977 subdocument = false; 978 try { 979 entryElement.closeEntry(); 980 } catch (IOException ex) { 981 throw new SAXException (ex.toString(), ex); 982 } 983 } 984 } 985 } 986 987 public final void startDocument() throws SAXException { 988 } 989 990 public final void endDocument() throws SAXException { 991 } 992 993 public final void characters(char[] buff, int offset, int size) 994 throws SAXException 995 { 996 if (subdocument) { 997 subdocumentHandler.characters(buff, offset, size); 998 } 999 } 1000 1001 } 1002 1003 private static interface EntryElement { 1004 1005 OutputStream openEntry(String name) throws IOException ; 1006 1007 void closeEntry() throws IOException ; 1008 1009 } 1010 1011 private static final class SingleDocElement implements EntryElement { 1012 private OutputStream os; 1013 1014 public SingleDocElement(OutputStream os) { 1015 this.os = os; 1016 } 1017 1018 public OutputStream openEntry(String name) throws IOException { 1019 return os; 1020 } 1021 1022 public void closeEntry() throws IOException { 1023 os.flush(); 1024 } 1025 1026 } 1027 1028 private static final class ZipEntryElement implements EntryElement { 1029 private ZipOutputStream zos; 1030 1031 public ZipEntryElement(ZipOutputStream zos) { 1032 this.zos = zos; 1033 } 1034 1035 public OutputStream openEntry(String name) throws IOException { 1036 ZipEntry entry = new ZipEntry (name); 1037 zos.putNextEntry(entry); 1038 return zos; 1039 } 1040 1041 public void closeEntry() throws IOException { 1042 zos.flush(); 1043 zos.closeEntry(); 1044 } 1045 1046 } 1047 1048} 1049 | Popular Tags |