1/*
2 * Copyright (c) 2005, 2016, 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.org.apache.xalan.internal.xsltc.trax;
27
28import java.io.IOException;
29import org.xml.sax.Attributes;
30import org.xml.sax.ContentHandler;
31import org.xml.sax.DTDHandler;
32import org.xml.sax.EntityResolver;
33import org.xml.sax.ErrorHandler;
34import org.xml.sax.InputSource;
35import org.xml.sax.Locator;
36import org.xml.sax.SAXException;
37import org.xml.sax.SAXNotRecognizedException;
38import org.xml.sax.SAXNotSupportedException;
39import org.xml.sax.XMLReader;
40import org.xml.sax.ext.LexicalHandler;
41import org.xml.sax.ext.Locator2;
42import org.xml.sax.helpers.AttributesImpl;
43import com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl;
44
45
46
47import javax.xml.namespace.QName;
48import javax.xml.stream.XMLStreamReader;
49import javax.xml.stream.XMLStreamConstants;
50import javax.xml.stream.XMLStreamException;
51
52
53
54/**
55 * @author Padmaja Vedula
56 * @author Sunitha Reddy
57 */
58public class StAXStream2SAX implements XMLReader, Locator {
59
60    //private final static String EMPTYSTRING = "";
61    //private static final String XMLNS_PREFIX = "xmlns";
62
63    // StAX Stream source
64    private final XMLStreamReader staxStreamReader;
65
66    //private Node _dom = null;
67    private ContentHandler _sax = null;
68    private LexicalHandler _lex = null;
69    private SAXImpl _saxImpl = null;
70
71    public StAXStream2SAX(XMLStreamReader staxSrc) {
72            staxStreamReader = staxSrc;
73    }
74
75    public ContentHandler getContentHandler() {
76        return _sax;
77    }
78
79    public void setContentHandler(ContentHandler handler) throws
80        NullPointerException
81    {
82        _sax = handler;
83        if (handler instanceof LexicalHandler) {
84            _lex = (LexicalHandler) handler;
85        }
86
87        if (handler instanceof SAXImpl) {
88            _saxImpl = (SAXImpl)handler;
89        }
90    }
91
92
93    public void parse(InputSource unused) throws IOException, SAXException {
94        try {
95            bridge();
96        } catch (XMLStreamException e) {
97            throw new SAXException(e);
98        }
99    }
100
101
102    //Main Work Starts Here.
103    public void parse() throws IOException, SAXException, XMLStreamException {
104        bridge();
105    }
106
107
108   /**
109     * This class is only used internally so this method should never
110     * be called.
111     */
112    public void parse(String sysId) throws IOException, SAXException {
113        throw new IOException("This method is not yet implemented.");
114    }
115
116
117   public void bridge() throws XMLStreamException {
118
119        try {
120            // remembers the nest level of elements to know when we are done.
121            int depth=0;
122
123            // skip over START_DOCUMENT
124            int event = staxStreamReader.getEventType();
125            if (event == XMLStreamConstants.START_DOCUMENT) {
126                event = staxStreamReader.next();
127            }
128
129            // If not a START_ELEMENT (e.g., a DTD), skip to next tag
130            if (event != XMLStreamConstants.START_ELEMENT) {
131                event = staxStreamReader.nextTag();
132                // An error if a START_ELEMENT isn't found now
133                if (event != XMLStreamConstants.START_ELEMENT) {
134                    throw new IllegalStateException("The current event is " +
135                            "not START_ELEMENT\n but" + event);
136                }
137            }
138
139            handleStartDocument();
140
141            do {
142                // These are all of the events listed in the javadoc for
143                // XMLEvent.
144                // The spec only really describes 11 of them.
145                switch (event) {
146                    case XMLStreamConstants.START_ELEMENT :
147                        depth++;
148                        handleStartElement();
149                        break;
150                    case XMLStreamConstants.END_ELEMENT :
151                        handleEndElement();
152                        depth--;
153                        break;
154                    case XMLStreamConstants.CHARACTERS :
155                        handleCharacters();
156                        break;
157                    case XMLStreamConstants.ENTITY_REFERENCE :
158                        handleEntityReference();
159                        break;
160                    case XMLStreamConstants.PROCESSING_INSTRUCTION :
161                        handlePI();
162                        break;
163                    case XMLStreamConstants.COMMENT :
164                        handleComment();
165                        break;
166                    case XMLStreamConstants.DTD :
167                        handleDTD();
168                        break;
169                    case XMLStreamConstants.ATTRIBUTE :
170                        handleAttribute();
171                        break;
172                    case XMLStreamConstants.NAMESPACE :
173                        handleNamespace();
174                        break;
175                    case XMLStreamConstants.CDATA :
176                        handleCDATA();
177                        break;
178                    case XMLStreamConstants.ENTITY_DECLARATION :
179                        handleEntityDecl();
180                        break;
181                    case XMLStreamConstants.NOTATION_DECLARATION :
182                        handleNotationDecl();
183                        break;
184                    case XMLStreamConstants.SPACE :
185                        handleSpace();
186                        break;
187                    default :
188                        throw new InternalError("processing event: " + event);
189                }
190
191                event=staxStreamReader.next();
192            } while (depth!=0);
193
194            handleEndDocument();
195        } catch (SAXException e) {
196            throw new XMLStreamException(e);
197        }
198    }
199
200    private void handleEndDocument() throws SAXException {
201        _sax.endDocument();
202    }
203
204    private void handleStartDocument() throws SAXException {
205        _sax.setDocumentLocator(new Locator2() {
206            public int getColumnNumber() {
207                return staxStreamReader.getLocation().getColumnNumber();
208            }
209            public int getLineNumber() {
210                return staxStreamReader.getLocation().getLineNumber();
211            }
212            public String getPublicId() {
213                return staxStreamReader.getLocation().getPublicId();
214            }
215            public String getSystemId() {
216                return staxStreamReader.getLocation().getSystemId();
217            }
218            public String getXMLVersion() {
219                return staxStreamReader.getVersion();
220            }
221            public String getEncoding() {
222                return staxStreamReader.getEncoding();
223            }
224         });
225        _sax.startDocument();
226    }
227
228    private void handlePI() throws XMLStreamException {
229        try {
230            _sax.processingInstruction(
231                staxStreamReader.getPITarget(),
232                staxStreamReader.getPIData());
233        } catch (SAXException e) {
234            throw new XMLStreamException(e);
235        }
236    }
237
238    private void handleCharacters() throws XMLStreamException {
239
240        // workaround for bugid 5046319 - switch over to commented section
241        // below when it is fixed.
242        int textLength = staxStreamReader.getTextLength();
243        char[] chars = new char[textLength];
244
245        staxStreamReader.getTextCharacters(0, chars, 0, textLength);
246
247        try {
248            _sax.characters(chars, 0, chars.length);
249        } catch (SAXException e) {
250            throw new XMLStreamException(e);
251        }
252
253
254//        int start = 0;
255//        int len;
256//        do {
257//            len = staxStreamReader.getTextCharacters(start, buf, 0, buf.length);
258//            start += len;
259//            try {
260//                _sax.characters(buf, 0, len);
261//            } catch (SAXException e) {
262//                throw new XMLStreamException(e);
263//            }
264//        } while (len == buf.length);
265    }
266
267    private void handleEndElement() throws XMLStreamException {
268        QName qName = staxStreamReader.getName();
269
270        try {
271            //construct prefix:localName from qName
272            String qname = "";
273            if (qName.getPrefix() != null && qName.getPrefix().trim().length() != 0){
274                qname = qName.getPrefix() + ":";
275            }
276            qname += qName.getLocalPart();
277
278            // fire endElement
279            _sax.endElement(
280                qName.getNamespaceURI(),
281                qName.getLocalPart(),
282                qname);
283
284            // end namespace bindings
285            int nsCount = staxStreamReader.getNamespaceCount();
286            for (int i = nsCount - 1; i >= 0; i--) {
287                String prefix = staxStreamReader.getNamespacePrefix(i);
288                if (prefix == null) { // true for default namespace
289                    prefix = "";
290                }
291                _sax.endPrefixMapping(prefix);
292            }
293        } catch (SAXException e) {
294            throw new XMLStreamException(e);
295        }
296    }
297
298    private void handleStartElement() throws XMLStreamException {
299
300        try {
301            // start namespace bindings
302            int nsCount = staxStreamReader.getNamespaceCount();
303            for (int i = 0; i < nsCount; i++) {
304                String prefix = staxStreamReader.getNamespacePrefix(i);
305                if (prefix == null) { // true for default namespace
306                    prefix = "";
307                }
308                String uri = staxStreamReader.getNamespaceURI(i);
309                if (uri == null && prefix.isEmpty()) { // true for default namespace
310                    uri = "";
311                }
312
313                _sax.startPrefixMapping(prefix, uri);
314            }
315
316            // fire startElement
317            QName qName = staxStreamReader.getName();
318            String prefix = qName.getPrefix();
319            String rawname;
320            if(prefix==null || prefix.length()==0)
321                rawname = qName.getLocalPart();
322            else
323                rawname = prefix + ':' + qName.getLocalPart();
324            Attributes attrs = getAttributes();
325            _sax.startElement(
326                qName.getNamespaceURI(),
327                qName.getLocalPart(),
328                rawname,
329                attrs);
330        } catch (SAXException e) {
331            throw new XMLStreamException(e);
332        }
333    }
334
335    /**
336     * Get the attributes associated with the given START_ELEMENT or ATTRIBUTE
337     * StAXevent.
338     *
339     * @return the StAX attributes converted to an org.xml.sax.Attributes
340     */
341    private Attributes getAttributes() {
342        AttributesImpl attrs = new AttributesImpl();
343
344        int eventType = staxStreamReader.getEventType();
345        if (eventType != XMLStreamConstants.ATTRIBUTE
346            && eventType != XMLStreamConstants.START_ELEMENT) {
347            throw new InternalError(
348                "getAttributes() attempting to process: " + eventType);
349        }
350
351        // in SAX, namespace declarations are not part of attributes by default.
352        // (there's a property to control that, but as far as we are concerned
353        // we don't use it.) So don't add xmlns:* to attributes.
354
355        // gather non-namespace attrs
356        for (int i = 0; i < staxStreamReader.getAttributeCount(); i++) {
357            String uri = staxStreamReader.getAttributeNamespace(i);
358            if(uri==null)   uri="";
359            String localName = staxStreamReader.getAttributeLocalName(i);
360            String prefix = staxStreamReader.getAttributePrefix(i);
361            String qName;
362            if(prefix==null || prefix.length()==0)
363                qName = localName;
364            else
365                qName = prefix + ':' + localName;
366            String type = staxStreamReader.getAttributeType(i);
367            String value = staxStreamReader.getAttributeValue(i);
368
369            attrs.addAttribute(uri, localName, qName, type, value);
370        }
371
372        return attrs;
373    }
374
375    private void handleNamespace() {
376        // no-op ???
377        // namespace events don't normally occur outside of a startElement
378        // or endElement
379    }
380
381    private void handleAttribute() {
382        // no-op ???
383        // attribute events don't normally occur outside of a startElement
384        // or endElement
385    }
386
387    private void handleDTD() {
388        // no-op ???
389        // it seems like we need to pass this info along, but how?
390    }
391
392    private void handleComment() {
393        // no-op ???
394    }
395
396    private void handleEntityReference() {
397        // no-op ???
398    }
399
400    private void handleSpace() {
401        // no-op ???
402        // this event is listed in the javadoc, but not in the spec.
403    }
404
405    private void handleNotationDecl() {
406        // no-op ???
407        // this event is listed in the javadoc, but not in the spec.
408    }
409
410    private void handleEntityDecl() {
411        // no-op ???
412        // this event is listed in the javadoc, but not in the spec.
413    }
414
415    private void handleCDATA() {
416        // no-op ???
417        // this event is listed in the javadoc, but not in the spec.
418    }
419
420
421    /**
422     * This class is only used internally so this method should never
423     * be called.
424     */
425    public DTDHandler getDTDHandler() {
426        return null;
427    }
428
429    /**
430     * This class is only used internally so this method should never
431     * be called.
432     */
433    public ErrorHandler getErrorHandler() {
434        return null;
435    }
436
437    /**
438     * This class is only used internally so this method should never
439     * be called.
440     */
441    public boolean getFeature(String name) throws SAXNotRecognizedException,
442        SAXNotSupportedException
443    {
444        return false;
445    }
446
447    /**
448     * This class is only used internally so this method should never
449     * be called.
450     */
451    public void setFeature(String name, boolean value) throws
452        SAXNotRecognizedException, SAXNotSupportedException
453    {
454    }
455
456    /**
457     * This class is only used internally so this method should never
458     * be called.
459     */
460    public void setDTDHandler(DTDHandler handler) throws NullPointerException {
461    }
462
463    /**
464     * This class is only used internally so this method should never
465     * be called.
466     */
467    public void setEntityResolver(EntityResolver resolver) throws
468        NullPointerException
469    {
470    }
471
472    /**
473     * This class is only used internally so this method should never
474     * be called.
475     */
476    public EntityResolver getEntityResolver() {
477        return null;
478    }
479
480    /**
481     * This class is only used internally so this method should never
482     * be called.
483     */
484    public void setErrorHandler(ErrorHandler handler) throws
485        NullPointerException
486    {
487    }
488
489    /**
490     * This class is only used internally so this method should never
491     * be called.
492     */
493    public void setProperty(String name, Object value) throws
494        SAXNotRecognizedException, SAXNotSupportedException {
495    }
496
497    /**
498     * This class is only used internally so this method should never
499     * be called.
500     */
501    public Object getProperty(String name) throws SAXNotRecognizedException,
502        SAXNotSupportedException
503    {
504        return null;
505    }
506
507    /**
508     * This class is only used internally so this method should never
509     * be called.
510     */
511    public int getColumnNumber() {
512        return 0;
513    }
514
515    /**
516     * This class is only used internally so this method should never
517     * be called.
518     */
519    public int getLineNumber() {
520        return 0;
521    }
522
523    /**
524     * This class is only used internally so this method should never
525     * be called.
526     */
527    public String getPublicId() {
528        return null;
529    }
530
531    /**
532     * This class is only used internally so this method should never
533     * be called.
534     */
535    public String getSystemId() {
536        return null;
537    }
538
539}
540