1/*
2 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.xml.internal.stream.buffer.sax;
27
28import com.sun.xml.internal.stream.buffer.AbstractCreator;
29import org.xml.sax.Attributes;
30import org.xml.sax.SAXException;
31import com.sun.xml.internal.stream.buffer.MutableXMLStreamBuffer;
32import java.io.IOException;
33import java.io.InputStream;
34import org.xml.sax.ContentHandler;
35import org.xml.sax.DTDHandler;
36import org.xml.sax.EntityResolver;
37import org.xml.sax.ErrorHandler;
38import org.xml.sax.InputSource;
39import org.xml.sax.Locator;
40import org.xml.sax.SAXParseException;
41import org.xml.sax.XMLReader;
42import org.xml.sax.ext.LexicalHandler;
43
44/**
45 * Writes into {@link MutableXMLStreamBuffer} from SAX.
46 *
47 * TODO
48 * Implement the marking the stream on the element when an ID
49 * attribute on the element is defined
50 */
51public class SAXBufferCreator extends AbstractCreator
52        implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler, LexicalHandler {
53    protected String[] _namespaceAttributes;
54
55    protected int _namespaceAttributesPtr;
56
57    private int depth = 0;
58
59    public SAXBufferCreator() {
60        _namespaceAttributes = new String[16 * 2];
61    }
62
63    public SAXBufferCreator(MutableXMLStreamBuffer buffer) {
64        this();
65        setBuffer(buffer);
66    }
67
68    public MutableXMLStreamBuffer create(XMLReader reader, InputStream in) throws IOException, SAXException {
69        return create(reader, in, null);
70    }
71
72    public MutableXMLStreamBuffer create(XMLReader reader, InputStream in, String systemId) throws IOException, SAXException {
73        if (_buffer == null) {
74            createBuffer();
75        }
76        _buffer.setSystemId(systemId);
77        reader.setContentHandler(this);
78        reader.setProperty(Properties.LEXICAL_HANDLER_PROPERTY, this);
79
80        try {
81            setHasInternedStrings(reader.getFeature(Features.STRING_INTERNING_FEATURE));
82        } catch (SAXException e) {
83        }
84
85
86        if (systemId != null) {
87            InputSource s = new InputSource(systemId);
88            s.setByteStream(in);
89            reader.parse(s);
90        } else {
91            reader.parse(new InputSource(in));
92        }
93
94        return getXMLStreamBuffer();
95    }
96
97    public void reset() {
98        _buffer = null;
99        _namespaceAttributesPtr = 0;
100        depth=0;
101    }
102
103    public void startDocument() throws SAXException {
104        storeStructure(T_DOCUMENT);
105    }
106
107    public void endDocument() throws SAXException {
108        storeStructure(T_END);
109    }
110
111    public void startPrefixMapping(String prefix, String uri) throws SAXException {
112        cacheNamespaceAttribute(prefix, uri);
113    }
114
115    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
116        storeQualifiedName(T_ELEMENT_LN,
117                uri, localName, qName);
118
119        // Has namespaces attributes
120        if (_namespaceAttributesPtr > 0) {
121            storeNamespaceAttributes();
122        }
123
124        // Has attributes
125        if (attributes.getLength() > 0) {
126            storeAttributes(attributes);
127        }
128        depth++;
129    }
130
131    public void endElement(String uri, String localName, String qName) throws SAXException {
132        storeStructure(T_END);
133        if(--depth==0)
134            increaseTreeCount();    // one tree processed
135    }
136
137    public void characters(char ch[], int start, int length) throws SAXException {
138        storeContentCharacters(T_TEXT_AS_CHAR_ARRAY, ch, start, length);
139    }
140
141    public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
142        characters(ch, start, length);
143    }
144
145    public void processingInstruction(String target, String data) throws SAXException {
146        storeStructure(T_PROCESSING_INSTRUCTION);
147        storeStructureString(target);
148        storeStructureString(data);
149    }
150
151    public void comment(char[] ch, int start, int length) throws SAXException {
152        storeContentCharacters(T_COMMENT_AS_CHAR_ARRAY, ch, start, length);
153    }
154
155    //
156
157    private void cacheNamespaceAttribute(String prefix, String uri) {
158        _namespaceAttributes[_namespaceAttributesPtr++] = prefix;
159        _namespaceAttributes[_namespaceAttributesPtr++] = uri;
160
161        if (_namespaceAttributesPtr == _namespaceAttributes.length) {
162            final String[] namespaceAttributes = new String[_namespaceAttributesPtr * 2];
163            System.arraycopy(_namespaceAttributes, 0, namespaceAttributes, 0, _namespaceAttributesPtr);
164            _namespaceAttributes = namespaceAttributes;
165        }
166    }
167
168    private void storeNamespaceAttributes() {
169        for (int i = 0; i < _namespaceAttributesPtr; i += 2) {
170            int item = T_NAMESPACE_ATTRIBUTE;
171            if (_namespaceAttributes[i].length() > 0) {
172                item |= FLAG_PREFIX;
173                storeStructureString(_namespaceAttributes[i]);
174            }
175            if (_namespaceAttributes[i + 1].length() > 0) {
176                item |= FLAG_URI;
177                storeStructureString(_namespaceAttributes[i + 1]);
178            }
179            storeStructure(item);
180        }
181        _namespaceAttributesPtr = 0;
182    }
183
184    private void storeAttributes(Attributes attributes) {
185        for (int i = 0; i < attributes.getLength(); i++) {
186            // Skip NS attributes. Some versions of JDK seem to send wrong local name
187            // Also it is not stored correctly by the following.
188            if (attributes.getQName(i).startsWith("xmlns"))
189                continue;
190            storeQualifiedName(T_ATTRIBUTE_LN,
191                    attributes.getURI(i),
192                    attributes.getLocalName(i),
193                    attributes.getQName(i));
194
195            storeStructureString(attributes.getType(i));
196            storeContentString(attributes.getValue(i));
197        }
198    }
199
200    private void storeQualifiedName(int item, String uri, String localName, String qName) {
201        if (uri.length() > 0) {
202            item |= FLAG_URI;
203            storeStructureString(uri);
204        }
205
206        storeStructureString(localName);
207
208        if (qName.indexOf(':') >= 0) {
209            item |= FLAG_QUALIFIED_NAME;
210            storeStructureString(qName);
211        }
212
213        storeStructure(item);
214    }
215
216
217    // Empty methods for SAX handlers
218
219    // Entity resolver handler
220
221    public InputSource resolveEntity (String publicId, String systemId)
222        throws IOException, SAXException
223    {
224        return null;
225    }
226
227    // DTD handler
228
229    public void notationDecl (String name, String publicId, String systemId)
230        throws SAXException
231    { }
232
233    public void unparsedEntityDecl (String name, String publicId,
234                                    String systemId, String notationName)
235        throws SAXException
236    { }
237
238    // Content handler
239
240    public void setDocumentLocator (Locator locator) { }
241
242    public void endPrefixMapping (String prefix) throws SAXException { }
243
244    public void skippedEntity (String name) throws SAXException { }
245
246    // Lexical handler
247
248    public void startDTD(String name, String publicId, String systemId) throws SAXException { }
249
250    public void endDTD() throws SAXException { }
251
252    public void startEntity(String name) throws SAXException { }
253
254    public void endEntity(String name) throws SAXException { }
255
256    public void startCDATA() throws SAXException { }
257
258    public void endCDATA() throws SAXException { }
259
260    // Error handler
261
262    public void warning(SAXParseException e) throws SAXException { }
263
264    public void error(SAXParseException e) throws SAXException { }
265
266    public void fatalError(SAXParseException e) throws SAXException
267    {
268        throw e;
269    }
270}
271