1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * you may not use this file except in compliance with the License.
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * You may obtain a copy of the License at
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.xml;
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
197365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.io.IOException;
207365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.io.InputStream;
217365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.io.Reader;
227365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.net.URI;
237365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.net.URL;
247365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.net.URLConnection;
25a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilsonimport libcore.io.IoUtils;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.Attributes;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.ContentHandler;
28c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughesimport org.xml.sax.DTDHandler;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.EntityResolver;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.InputSource;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.Locator;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.SAXException;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.SAXParseException;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.ext.LexicalHandler;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Adapts SAX API to the Expat native XML parser. Not intended for reuse
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * across documents.
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see org.apache.harmony.xml.ExpatReader
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectclass ExpatParser {
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int BUFFER_SIZE = 8096; // in bytes
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /** Pointer to XML_Parser instance. */
470b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice    private long pointer;
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean inStartElement = false;
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int attributeCount = -1;
518107b206cd72c51ffaeac1f7fcfdf4ea0728e34cElliott Hughes    private long attributePointer = 0;
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final Locator locator = new ExpatLocator();
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final ExpatReader xmlReader;
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final String publicId;
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final String systemId;
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final String encoding;
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final ExpatAttributes attributes = new CurrentAttributes();
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final String OUTSIDE_START_ELEMENT
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            = "Attributes can only be used within the scope of startElement().";
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /** We default to UTF-8 when the user doesn't specify an encoding. */
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final String DEFAULT_ENCODING = "UTF-8";
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /** Encoding used for Java chars, used to parse Readers and Strings */
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ static final String CHARACTER_ENCODING = "UTF-16";
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /** Timeout for HTTP connections (in ms) */
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int TIMEOUT = 20 * 1000;
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new parser with the specified encoding.
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ ExpatParser(String encoding, ExpatReader xmlReader,
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            boolean processNamespaces, String publicId, String systemId) {
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.publicId = publicId;
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.systemId = systemId;
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.xmlReader = xmlReader;
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * TODO: Let Expat try to guess the encoding instead of defaulting.
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Unfortunately, I don't know how to tell which encoding Expat picked,
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * so I won't know how to encode "<externalEntity>" below. The solution
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * I think is to fix Expat to not require the "<externalEntity>"
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * workaround.
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.encoding = encoding == null ? DEFAULT_ENCODING : encoding;
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.pointer = initialize(
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.encoding,
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            processNamespaces
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        );
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Used by {@link EntityParser}.
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1030b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice    private ExpatParser(String encoding, ExpatReader xmlReader, long pointer,
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String publicId, String systemId) {
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.encoding = encoding;
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.xmlReader = xmlReader;
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.pointer = pointer;
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.systemId = systemId;
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.publicId = publicId;
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Initializes native resources.
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the pointer to the native parser
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1170b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice    private native long initialize(String encoding, boolean namespacesEnabled);
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Called at the start of an element.
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param uri namespace URI of element or "" if namespace processing is
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *  disabled
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param localName local name of element or "" if namespace processing is
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *  disabled
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param qName qualified name or "" if namespace processing is enabled
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param attributePointer pointer to native attribute char*--we keep
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *  a separate pointer so we can detach it from the parser instance
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param attributeCount number of attributes
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void startElement(String uri, String localName, String qName,
1328107b206cd72c51ffaeac1f7fcfdf4ea0728e34cElliott Hughes            long attributePointer, int attributeCount) throws SAXException {
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ContentHandler contentHandler = xmlReader.contentHandler;
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (contentHandler == null) {
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            inStartElement = true;
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.attributePointer = attributePointer;
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.attributeCount = attributeCount;
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            contentHandler.startElement(
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    uri, localName, qName, this.attributes);
145e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            inStartElement = false;
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.attributeCount = -1;
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.attributePointer = 0;
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void endElement(String uri, String localName, String qName)
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws SAXException {
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ContentHandler contentHandler = xmlReader.contentHandler;
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (contentHandler != null) {
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            contentHandler.endElement(uri, localName, qName);
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void text(char[] text, int length) throws SAXException {
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ContentHandler contentHandler = xmlReader.contentHandler;
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (contentHandler != null) {
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            contentHandler.characters(text, 0, length);
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void comment(char[] text, int length) throws SAXException {
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        LexicalHandler lexicalHandler = xmlReader.lexicalHandler;
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (lexicalHandler != null) {
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            lexicalHandler.comment(text, 0, length);
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void startCdata() throws SAXException {
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        LexicalHandler lexicalHandler = xmlReader.lexicalHandler;
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (lexicalHandler != null) {
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            lexicalHandler.startCDATA();
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void endCdata() throws SAXException {
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        LexicalHandler lexicalHandler = xmlReader.lexicalHandler;
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (lexicalHandler != null) {
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            lexicalHandler.endCDATA();
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void startNamespace(String prefix, String uri)
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws SAXException {
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ContentHandler contentHandler = xmlReader.contentHandler;
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (contentHandler != null) {
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            contentHandler.startPrefixMapping(prefix, uri);
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void endNamespace(String prefix) throws SAXException {
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ContentHandler contentHandler = xmlReader.contentHandler;
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (contentHandler != null) {
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            contentHandler.endPrefixMapping(prefix);
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void startDtd(String name, String publicId, String systemId)
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws SAXException {
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        LexicalHandler lexicalHandler = xmlReader.lexicalHandler;
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (lexicalHandler != null) {
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            lexicalHandler.startDTD(name, publicId, systemId);
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void endDtd() throws SAXException {
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        LexicalHandler lexicalHandler = xmlReader.lexicalHandler;
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (lexicalHandler != null) {
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            lexicalHandler.endDTD();
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void processingInstruction(String target, String data)
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws SAXException {
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ContentHandler contentHandler = xmlReader.contentHandler;
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (contentHandler != null) {
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            contentHandler.processingInstruction(target, data);
223f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        }
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
226c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes    /*package*/ void notationDecl(String name, String publicId, String systemId) throws SAXException {
227c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes        DTDHandler dtdHandler = xmlReader.dtdHandler;
228c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes        if (dtdHandler != null) {
229c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes            dtdHandler.notationDecl(name, publicId, systemId);
230c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes        }
231c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes    }
232c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes
233c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes    /*package*/ void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException {
234c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes        DTDHandler dtdHandler = xmlReader.dtdHandler;
235c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes        if (dtdHandler != null) {
236c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes            dtdHandler.unparsedEntityDecl(name, publicId, systemId, notationName);
237c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes        }
238c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes    }
239c9b92b4c79529c5308b2621ac1abe9a5ab039f8dElliott Hughes
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Handles an external entity.
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param context to be passed back to Expat when we parse the entity
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param publicId the publicId of the entity
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param systemId the systemId of the entity
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void handleExternalEntity(String context, String publicId,
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String systemId) throws SAXException, IOException {
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        EntityResolver entityResolver = xmlReader.entityResolver;
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (entityResolver == null) {
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * The spec. is terribly under-specified here. It says that if the
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * systemId is a URL, we should try to resolve it, but it doesn't
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * specify how to tell whether or not the systemId is a URL let alone
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * how to resolve it.
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         *
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Other implementations do various insane things. We try to keep it
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * simple: if the systemId parses as a URI and it's relative, we try to
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * resolve it against the parent document's systemId. If anything goes
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * wrong, we go with the original systemId. If crazybob had designed
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * the API, he would have left all resolving to the EntityResolver.
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (this.systemId != null) {
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                URI systemUri = new URI(systemId);
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (!systemUri.isAbsolute() && !systemUri.isOpaque()) {
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // It could be relative (or it may not be a URI at all!)
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    URI baseUri = new URI(this.systemId);
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    systemUri = baseUri.resolve(systemUri);
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Replace systemId w/ resolved URI
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    systemId = systemUri.toString();
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (Exception e) {
278a7ef55258ac71153487357b861c7639d627df82fElliott Hughes                System.logI("Could not resolve '" + systemId + "' relative to"
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        + " '" + this.systemId + "' at " + locator, e);
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InputSource inputSource = entityResolver.resolveEntity(
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                publicId, systemId);
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (inputSource == null) {
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /*
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * The spec. actually says that we should try to treat systemId
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * as a URL and download and parse its contents here, but an
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * entity resolver can easily accomplish the same by returning
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * new InputSource(systemId).
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             *
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * Downloading external entities by default would result in several
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * unwanted DTD downloads, not to mention pose a security risk
294e810d3b49631329b11440aa5b7a54db181d42ed1Elliott Hughes             * when parsing untrusted XML -- see for example
295e810d3b49631329b11440aa5b7a54db181d42ed1Elliott Hughes             * http://archive.cert.uni-stuttgart.de/bugtraq/2002/10/msg00421.html --
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * so we just do nothing instead. This also enables the user to
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * opt out of entity parsing when using
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * {@link org.xml.sax.helpers.DefaultHandler}, something that
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * wouldn't be possible otherwise.
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String encoding = pickEncoding(inputSource);
3050b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice        long pointer = createEntityParser(this.pointer, context);
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            EntityParser entityParser = new EntityParser(encoding, xmlReader,
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    pointer, inputSource.getPublicId(),
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    inputSource.getSystemId());
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            parseExternalEntity(entityParser, inputSource);
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } finally {
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            releaseParser(pointer);
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Picks an encoding for an external entity. Defaults to UTF-8.
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private String pickEncoding(InputSource inputSource) {
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Reader reader = inputSource.getCharacterStream();
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reader != null) {
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return CHARACTER_ENCODING;
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String encoding = inputSource.getEncoding();
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return encoding == null ? DEFAULT_ENCODING : encoding;
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Parses the the external entity provided by the input source.
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void parseExternalEntity(ExpatParser entityParser,
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            InputSource inputSource) throws IOException, SAXException {
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Expat complains if the external entity isn't wrapped with a root
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * element so we add one and ignore it later on during parsing.
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
339f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Try the character stream.
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Reader reader = inputSource.getCharacterStream();
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reader != null) {
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                entityParser.append("<externalEntity>");
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                entityParser.parseFragment(reader);
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                entityParser.append("</externalEntity>");
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } finally {
348a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson                IoUtils.closeQuietly(reader);
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Try the byte stream.
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InputStream in = inputSource.getByteStream();
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (in != null) {
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                entityParser.append("<externalEntity>"
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        .getBytes(entityParser.encoding));
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                entityParser.parseFragment(in);
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                entityParser.append("</externalEntity>"
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        .getBytes(entityParser.encoding));
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } finally {
363a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson                IoUtils.closeQuietly(in);
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Make sure we use the user-provided systemId.
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String systemId = inputSource.getSystemId();
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (systemId == null) {
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // TODO: We could just try our systemId here.
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ParseException("No input specified.", locator);
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Try the system id.
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        in = openUrl(systemId);
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            entityParser.append("<externalEntity>"
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getBytes(entityParser.encoding));
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            entityParser.parseFragment(in);
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            entityParser.append("</externalEntity>"
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getBytes(entityParser.encoding));
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } finally {
384a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson            IoUtils.closeQuietly(in);
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates a native entity parser.
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param parentPointer pointer to parent Expat parser
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param context passed to {@link #handleExternalEntity}
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return pointer to native parser
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
3950b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice    private static native long createEntityParser(long parentPointer, String context);
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Appends part of an XML document. This parser will parse the given XML to
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the extent possible and dispatch to the appropriate methods.
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param xml a whole or partial snippet of XML
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws SAXException if an error occurs during parsing
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void append(String xml) throws SAXException {
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
406e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes            appendString(this.pointer, xml, false);
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (ExpatException e) {
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ParseException(e.getMessage(), this.locator);
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
4120b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice    private native void appendString(long pointer, String xml, boolean isFinal)
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws SAXException, ExpatException;
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Appends part of an XML document. This parser will parse the given XML to
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the extent possible and dispatch to the appropriate methods.
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param xml a whole or partial snippet of XML
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param offset into the char[]
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param length of characters to use
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws SAXException if an error occurs during parsing
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void append(char[] xml, int offset, int length)
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws SAXException {
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
427e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes            appendChars(this.pointer, xml, offset, length);
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (ExpatException e) {
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ParseException(e.getMessage(), this.locator);
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
4330b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice    private native void appendChars(long pointer, char[] xml, int offset,
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int length) throws SAXException, ExpatException;
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Appends part of an XML document. This parser will parse the given XML to
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the extent possible and dispatch to the appropriate methods.
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param xml a whole or partial snippet of XML
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws SAXException if an error occurs during parsing
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void append(byte[] xml) throws SAXException {
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        append(xml, 0, xml.length);
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Appends part of an XML document. This parser will parse the given XML to
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the extent possible and dispatch to the appropriate methods.
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param xml a whole or partial snippet of XML
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param offset into the byte[]
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param length of bytes to use
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws SAXException if an error occurs during parsing
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void append(byte[] xml, int offset, int length)
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws SAXException {
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
459e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes            appendBytes(this.pointer, xml, offset, length);
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (ExpatException e) {
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ParseException(e.getMessage(), this.locator);
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
4650b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice    private native void appendBytes(long pointer, byte[] xml, int offset,
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int length) throws SAXException, ExpatException;
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Parses an XML document from the given input stream.
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void parseDocument(InputStream in) throws IOException,
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            SAXException {
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        startDocument();
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        parseFragment(in);
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        finish();
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        endDocument();
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Parses an XML Document from the given reader.
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void parseDocument(Reader in) throws IOException, SAXException {
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        startDocument();
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        parseFragment(in);
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        finish();
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        endDocument();
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Parses XML from the given Reader.
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void parseFragment(Reader in) throws IOException, SAXException {
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        char[] buffer = new char[BUFFER_SIZE / 2];
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int length;
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while ((length = in.read(buffer)) != -1) {
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
497e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes                appendChars(this.pointer, buffer, 0, length);
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (ExpatException e) {
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new ParseException(e.getMessage(), locator);
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Parses XML from the given input stream.
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void parseFragment(InputStream in)
508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IOException, SAXException {
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] buffer = new byte[BUFFER_SIZE];
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int length;
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while ((length = in.read(buffer)) != -1) {
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
513e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes                appendBytes(this.pointer, buffer, 0, length);
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (ExpatException e) {
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new ParseException(e.getMessage(), this.locator);
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
520adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void startDocument() throws SAXException {
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ContentHandler contentHandler = xmlReader.contentHandler;
522adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (contentHandler != null) {
523adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            contentHandler.setDocumentLocator(this.locator);
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            contentHandler.startDocument();
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void endDocument() throws SAXException {
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ContentHandler contentHandler;
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        contentHandler = xmlReader.contentHandler;
531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (contentHandler != null) {
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            contentHandler.endDocument();
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicate that we're finished parsing.
538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws SAXException if the xml is incomplete
540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ void finish() throws SAXException {
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
543e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes            appendString(this.pointer, "", true);
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (ExpatException e) {
545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ParseException(e.getMessage(), this.locator);
546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
549e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected synchronized void finalize() throws Throwable {
550e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
551e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            if (this.pointer != 0) {
552e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                release(this.pointer);
553e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                this.pointer = 0;
554e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            }
555e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
556e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            super.finalize();
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Releases all native objects.
562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
5630b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice    private native void release(long pointer);
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Releases native parser only.
567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
5680b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice    private static native void releaseParser(long pointer);
569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Initialize static resources.
572adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
573adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static native void staticInitialize(String emptyString);
574adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static {
576adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        staticInitialize("");
577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the current line number within the XML file.
581adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int line() {
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return line(this.pointer);
584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
5860b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice    private static native int line(long pointer);
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
589adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the current column number within the XML file.
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int column() {
592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return column(this.pointer);
593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
5950b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice    private static native int column(long pointer);
596adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Clones the current attributes so they can be used outside of
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * startElement().
600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ Attributes cloneAttributes() {
602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!inStartElement) {
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalStateException(OUTSIDE_START_ELEMENT);
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (attributeCount == 0) {
607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return ClonedAttributes.EMPTY;
608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
609adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6100b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice        long clonePointer
611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                = cloneAttributes(this.attributePointer, this.attributeCount);
612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new ClonedAttributes(pointer, clonePointer, attributeCount);
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
614adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6150b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice    private static native long cloneAttributes(long pointer, int attributeCount);
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Used for cloned attributes.
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static class ClonedAttributes extends ExpatAttributes {
621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private static final Attributes EMPTY = new ClonedAttributes(0, 0, 0);
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6240b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice        private final long parserPointer;
6250b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice        private long pointer;
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private final int length;
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Constructs a Java wrapper for native attributes.
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         *
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @param parserPointer pointer to the parse, can be 0 if length is 0.
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @param pointer pointer to the attributes array, can be 0 if the
633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         *  length is 0.
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @param length number of attributes
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
6360b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice        private ClonedAttributes(long parserPointer, long pointer, int length) {
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.parserPointer = parserPointer;
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.pointer = pointer;
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.length = length;
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
6430b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice        public long getParserPointer() {
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return this.parserPointer;
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
6480b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice        public long getPointer() {
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return pointer;
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getLength() {
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return length;
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
657e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        @Override protected synchronized void finalize() throws Throwable {
658e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            try {
659e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                if (pointer != 0) {
660e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                    freeAttributes(pointer);
661e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                    pointer = 0;
662e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                }
663e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            } finally {
664e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                super.finalize();
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private class ExpatLocator implements Locator {
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
671adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public String getPublicId() {
672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return publicId;
673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public String getSystemId() {
676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return systemId;
677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getLineNumber() {
680adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return line();
681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getColumnNumber() {
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return column();
685adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public String toString() {
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return "Locator[publicId: " + publicId + ", systemId: " + systemId
690adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                + ", line: " + getLineNumber()
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                + ", column: " + getColumnNumber() + "]";
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
695adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
696adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Attributes that are only valid during startElement().
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private class CurrentAttributes extends ExpatAttributes {
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
7010b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice        public long getParserPointer() {
702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return pointer;
703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
7060b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice        public long getPointer() {
707adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!inStartElement) {
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalStateException(OUTSIDE_START_ELEMENT);
709adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return attributePointer;
711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
714adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getLength() {
715adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!inStartElement) {
716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalStateException(OUTSIDE_START_ELEMENT);
717adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return attributeCount;
719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Includes line and column in the message.
724adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static class ParseException extends SAXParseException {
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private ParseException(String message, Locator locator) {
728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            super(makeMessage(message, locator), locator);
729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
730adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private static String makeMessage(String message, Locator locator) {
732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return makeMessage(message, locator.getLineNumber(),
733adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    locator.getColumnNumber());
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
735adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private static String makeMessage(
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String message, int line, int column) {
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return "At line " + line + ", column "
739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    + column + ": " + message;
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
742f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
743adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
744adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Opens an InputStream for the given URL.
745adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*package*/ static InputStream openUrl(String url) throws IOException {
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            URLConnection urlConnection = new URL(url).openConnection();
749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            urlConnection.setConnectTimeout(TIMEOUT);
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            urlConnection.setReadTimeout(TIMEOUT);
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            urlConnection.setDoInput(true);
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            urlConnection.setDoOutput(false);
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return urlConnection.getInputStream();
754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            IOException ioe = new IOException("Couldn't open " + url);
756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ioe.initCause(e);
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw ioe;
758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Parses an external entity.
763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
764adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static class EntityParser extends ExpatParser {
765adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
766f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        private int depth = 0;
767adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
768adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private EntityParser(String encoding, ExpatReader xmlReader,
7690b00d81d3c9e9a2df4635cd6a55e291cce303658Joel Dice                long pointer, String publicId, String systemId) {
770adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            super(encoding, xmlReader, pointer, publicId, systemId);
771adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
772adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
773adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
774adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        void startElement(String uri, String localName, String qName,
7758107b206cd72c51ffaeac1f7fcfdf4ea0728e34cElliott Hughes                long attributePointer, int attributeCount) throws SAXException {
776adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /*
777adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * Skip topmost element generated by our workaround in
778adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * {@link #handleExternalEntity}.
779adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (depth++ > 0) {
781adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                super.startElement(uri, localName, qName, attributePointer,
782adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        attributeCount);
783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
784adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
785f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
786adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        void endElement(String uri, String localName, String qName)
788adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throws SAXException {
789adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (--depth > 0) {
790adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                super.endElement(uri, localName, qName);
791adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
792adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
793adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
794adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
795adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @SuppressWarnings("FinalizeDoesntCallSuperFinalize")
796adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        protected synchronized void finalize() throws Throwable {
797adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /*
798adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * Don't release our native resources. We do so explicitly in
799adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * {@link #handleExternalEntity} and we don't want to release the
800adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * parsing context--our parent is using it.
801adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
802adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
803adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
804adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
805