1 /******************************************************************************* 2 * Copyright (c) 2005, 2017 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.pde.internal.core.plugin; 15 16 import java.io.StringReader; 17 import java.util.Stack; 18 import java.util.regex.Matcher; 19 import java.util.regex.Pattern; 20 import javax.xml.parsers.DocumentBuilderFactory; 21 import javax.xml.parsers.ParserConfigurationException; 22 import org.eclipse.pde.internal.core.TargetPlatformHelper; 23 import org.eclipse.pde.internal.core.util.IdUtil; 24 import org.w3c.dom.DOMException; 25 import org.w3c.dom.Document; 26 import org.w3c.dom.Element; 27 import org.w3c.dom.Node; 28 import org.w3c.dom.Text; 29 import org.xml.sax.Attributes; 30 import org.xml.sax.InputSource; 31 import org.xml.sax.Locator; 32 import org.xml.sax.SAXException; 33 import org.xml.sax.helpers.DefaultHandler; 34 35 public class PluginHandler extends DefaultHandler { 36 private Document fDocument; 37 private Element fRootElement; 38 private final Stack<Element> fOpenElements = new Stack<>(); 39 40 private String fSchemaVersion; 41 private final boolean fAbbreviated; 42 private Locator fLocator; 43 private boolean fPop; 44 45 private static final Pattern VERSION_RE = Pattern.compile("version\\s*=\\s*\"([^\"]+)\""); //$NON-NLS-1$ 46 PluginHandler(boolean abbreviated)47 public PluginHandler(boolean abbreviated) { 48 fAbbreviated = abbreviated; 49 } 50 51 @Override startElement(String uri, String localName, String qName, Attributes attributes)52 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { 53 54 fPop = true; 55 56 if (fAbbreviated && fOpenElements.size() == 2) { 57 Element parent = fOpenElements.peek(); 58 if (parent.getNodeName().equals("extension") && !isInterestingExtension(fOpenElements.peek())) { //$NON-NLS-1$ 59 fPop = false; 60 return; 61 } 62 } 63 64 Element element = fDocument.createElement(qName); 65 for (int i = 0; i < attributes.getLength(); i++) { 66 element.setAttribute(attributes.getQName(i), attributes.getValue(i)); 67 if ("extension".equals(qName) || "extension-point".equals(qName)) { //$NON-NLS-1$ //$NON-NLS-2$ 68 element.setAttribute("line", Integer.toString(fLocator.getLineNumber())); //$NON-NLS-1$ 69 } 70 } 71 72 if (fRootElement == null) { 73 fRootElement = element; 74 } else { 75 fOpenElements.peek().appendChild(element); 76 } 77 78 fOpenElements.push(element); 79 } 80 isInterestingExtension(Element element)81 protected boolean isInterestingExtension(Element element) { 82 String point = element.getAttribute("point"); //$NON-NLS-1$ 83 return IdUtil.isInterestingExtensionPoint(point); 84 } 85 86 @Override endElement(String uri, String localName, String qName)87 public void endElement(String uri, String localName, String qName) throws SAXException { 88 if (fPop || (qName.equals("extension") && fOpenElements.size() == 2)) { //$NON-NLS-1$ 89 fOpenElements.pop(); 90 } 91 } 92 93 @Override setDocumentLocator(Locator locator)94 public void setDocumentLocator(Locator locator) { 95 fLocator = locator; 96 } 97 98 @Override startDocument()99 public void startDocument() throws SAXException { 100 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 101 try { 102 fDocument = factory.newDocumentBuilder().newDocument(); 103 } catch (ParserConfigurationException e) { 104 } 105 } 106 107 @Override endDocument()108 public void endDocument() throws SAXException { 109 fDocument.appendChild(fRootElement); 110 } 111 112 @Override processingInstruction(String target, String data)113 public void processingInstruction(String target, String data) throws SAXException { 114 if ("eclipse".equals(target)) { //$NON-NLS-1$ 115 // Data should be of the form: version="<version>" 116 data = data.trim(); 117 Matcher matcher = VERSION_RE.matcher(data); 118 if (matcher.matches()) { 119 fSchemaVersion = TargetPlatformHelper.getSchemaVersionForTargetVersion(matcher.group(1)); 120 } else { 121 fSchemaVersion = TargetPlatformHelper.getSchemaVersion(); 122 } 123 } 124 } 125 126 @Override characters(char[] characters, int start, int length)127 public void characters(char[] characters, int start, int length) throws SAXException { 128 if (fAbbreviated) { 129 return; 130 } 131 132 processCharacters(characters, start, length); 133 } 134 135 /** 136 * @param characters 137 * @param start 138 * @param length 139 * @throws DOMException 140 */ processCharacters(char[] characters, int start, int length)141 protected void processCharacters(char[] characters, int start, int length) throws DOMException { 142 StringBuilder buff = new StringBuilder(); 143 for (int i = 0; i < length; i++) { 144 buff.append(characters[start + i]); 145 } 146 Text text = fDocument.createTextNode(buff.toString()); 147 if (fRootElement == null) { 148 fDocument.appendChild(text); 149 } else { 150 fOpenElements.peek().appendChild(text); 151 } 152 } 153 getDocumentElement()154 public Node getDocumentElement() { 155 if (fRootElement != null) { 156 fRootElement.normalize(); 157 } 158 return fRootElement; 159 } 160 getSchemaVersion()161 public String getSchemaVersion() { 162 return fSchemaVersion; 163 } 164 165 @Override resolveEntity(String publicId, String systemId)166 public InputSource resolveEntity(String publicId, String systemId) throws SAXException { 167 // Prevent the resolution of external entities in order to 168 // prevent the parser from accessing the Internet 169 // This will prevent huge workbench performance degradations and hangs 170 return new InputSource(new StringReader("")); //$NON-NLS-1$ 171 } 172 173 } 174