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.parsers;
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
20c36982772a413bb14eb6d865013aac03544441d1Jesse Wilsonimport java.net.URL;
21c36982772a413bb14eb6d865013aac03544441d1Jesse Wilsonimport java.net.URLConnection;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.xml.parsers.DocumentBuilder;
23086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilsonimport libcore.io.IoUtils;
24bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilsonimport org.apache.harmony.xml.dom.CDATASectionImpl;
257365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport org.apache.harmony.xml.dom.DOMImplementationImpl;
26bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilsonimport org.apache.harmony.xml.dom.DocumentImpl;
278b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilsonimport org.apache.harmony.xml.dom.DocumentTypeImpl;
28bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilsonimport org.apache.harmony.xml.dom.TextImpl;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.kxml2.io.KXmlParser;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Attr;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.DOMImplementation;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Document;
33bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilsonimport org.w3c.dom.DocumentType;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Element;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Node;
36af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughesimport org.w3c.dom.Text;
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.EntityResolver;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.ErrorHandler;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.InputSource;
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.SAXException;
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.SAXParseException;
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.helpers.LocatorImpl;
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xmlpull.v1.XmlPullParser;
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException;
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
470463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson * Builds a DOM using KXmlParser.
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectclass DocumentBuilderImpl extends DocumentBuilder {
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
51bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    private static DOMImplementationImpl dom = DOMImplementationImpl.getInstance();
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
536bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes    private boolean coalescing;
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private EntityResolver entityResolver;
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private ErrorHandler errorHandler;
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean ignoreComments;
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean ignoreElementContentWhitespace;
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean namespaceAware;
5981bcd5c1f677de9c79155c87bcfbfc5896920403Jesse Wilson    // adding a new field? don't forget to update reset().
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6181bcd5c1f677de9c79155c87bcfbfc5896920403Jesse Wilson    @Override public void reset() {
6281bcd5c1f677de9c79155c87bcfbfc5896920403Jesse Wilson        coalescing = false;
6381bcd5c1f677de9c79155c87bcfbfc5896920403Jesse Wilson        entityResolver = null;
6481bcd5c1f677de9c79155c87bcfbfc5896920403Jesse Wilson        errorHandler = null;
6581bcd5c1f677de9c79155c87bcfbfc5896920403Jesse Wilson        ignoreComments = false;
6681bcd5c1f677de9c79155c87bcfbfc5896920403Jesse Wilson        ignoreElementContentWhitespace = false;
6781bcd5c1f677de9c79155c87bcfbfc5896920403Jesse Wilson        namespaceAware = false;
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public DOMImplementation getDOMImplementation() {
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return dom;
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean isNamespaceAware() {
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return namespaceAware;
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean isValidating() {
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return false;
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Document newDocument() {
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return dom.createDocument(null, null, null);
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Document parse(InputSource source) throws SAXException, IOException {
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (source == null) {
93086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson            throw new IllegalArgumentException("source == null");
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
95f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
96bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        String namespaceURI = null;
97bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        String qualifiedName = null;
98bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        DocumentType doctype = null;
995213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson        String inputEncoding = source.getEncoding();
1005213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson        String systemId = source.getSystemId();
1015213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson        DocumentImpl document = new DocumentImpl(
1025213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson                dom, namespaceURI, qualifiedName, doctype, inputEncoding);
1035213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson        document.setDocumentURI(systemId);
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
105086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson        KXmlParser parser = new KXmlParser();
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
1071ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            parser.keepNamespaceAttributes();
1085213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, namespaceAware);
1095213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (source.getByteStream() != null) {
1115213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson                parser.setInput(source.getByteStream(), inputEncoding);
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (source.getCharacterStream() != null) {
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                parser.setInput(source.getCharacterStream());
1145213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson            } else if (systemId != null) {
1155213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson                URL url = new URL(systemId);
116c36982772a413bb14eb6d865013aac03544441d1Jesse Wilson                URLConnection urlConnection = url.openConnection();
117c36982772a413bb14eb6d865013aac03544441d1Jesse Wilson                urlConnection.connect();
1185213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson                // TODO: if null, extract the inputEncoding from the Content-Type header?
1195213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson                parser.setInput(urlConnection.getInputStream(), inputEncoding);
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
121086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson                throw new SAXParseException("InputSource needs a stream, reader or URI", null);
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
124086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson            if (parser.nextToken() == XmlPullParser.END_DOCUMENT) {
125086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson                throw new SAXParseException("Unexpected end of document", null);
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            parse(parser, document, document, XmlPullParser.END_DOCUMENT);
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            parser.require(XmlPullParser.END_DOCUMENT, null, null);
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (XmlPullParserException ex) {
132086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson            if (ex.getDetail() instanceof IOException) {
133086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson                throw (IOException) ex.getDetail();
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
135086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson            if (ex.getDetail() instanceof RuntimeException) {
136086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson                throw (RuntimeException) ex.getDetail();
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
138f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            LocatorImpl locator = new LocatorImpl();
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            locator.setPublicId(source.getPublicId());
1425213a38431ea28c97d29e76c5b2d8e156c2d1705Jesse Wilson            locator.setSystemId(systemId);
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            locator.setLineNumber(ex.getLineNumber());
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            locator.setColumnNumber(ex.getColumnNumber());
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
146086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson            SAXParseException newEx = new SAXParseException(ex.getMessage(), locator);
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (errorHandler != null) {
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                errorHandler.error(newEx);
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw newEx;
153086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson        } finally {
154086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson            IoUtils.closeQuietly(parser);
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return document;
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Implements the whole parsing of the XML document. The XML pull parser is
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * actually more of a tokenizer, and we are doing a classical recursive
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * descent parsing (the method invokes itself for XML elements). Our
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * approach to parsing does accept some illegal documents (more than one
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * root element, for example). The assumption is that the DOM implementation
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * throws the proper exceptions in these cases.
167f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param parser The XML pull parser we're reading from.
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param document The document we're building.
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param node The node we're currently on (initially the document itself).
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param endToken The token that will end this recursive call. Either
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *        XmlPullParser.END_DOCUMENT or XmlPullParser.END_TAG.
173f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws XmlPullParserException If a parsing error occurs.
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException If a general IO error occurs.
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
177086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson    private void parse(KXmlParser parser, DocumentImpl document, Node node,
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int endToken) throws XmlPullParserException, IOException {
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int token = parser.getEventType();
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * The main parsing loop. The precondition is that we are already on the
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * token to be processed. This holds for each iteration of the loop, so
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * the inner statements have to ensure that (in particular the recursive
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * call).
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (token != endToken && token != XmlPullParser.END_DOCUMENT) {
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (token == XmlPullParser.PROCESSING_INSTRUCTION) {
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                /*
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * Found a processing instructions. We need to split the token
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * text at the first whitespace character.
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 */
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String text = parser.getText();
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int dot = text.indexOf(' ');
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String target = (dot != -1 ? text.substring(0, dot) : text);
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String data = (dot != -1 ? text.substring(dot + 1) : "");
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                node.appendChild(document.createProcessingInstruction(target,
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        data));
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (token == XmlPullParser.DOCDECL) {
204086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson                String name = parser.getRootElementName();
205086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson                String publicId = parser.getPublicId();
206086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson                String systemId = parser.getSystemId();
207086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson                document.appendChild(new DocumentTypeImpl(document, name, publicId, systemId));
208f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (token == XmlPullParser.COMMENT) {
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                /*
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * Found a comment. We simply take the token text, but we only
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * create a node if the client wants to see comments at all.
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 */
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (!ignoreComments) {
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    node.appendChild(document.createComment(parser.getText()));
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (token == XmlPullParser.IGNORABLE_WHITESPACE) {
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                /*
21903d1c3023ed8ff85ecb0a72d4f5615e6f81e31f6Jesse Wilson                 * Found some ignorable whitespace. We only add it if the client
22003d1c3023ed8ff85ecb0a72d4f5615e6f81e31f6Jesse Wilson                 * wants to see whitespace. Whitespace before and after the
22103d1c3023ed8ff85ecb0a72d4f5615e6f81e31f6Jesse Wilson                 * document element is always ignored.
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 */
22303d1c3023ed8ff85ecb0a72d4f5615e6f81e31f6Jesse Wilson                if (!ignoreElementContentWhitespace && document != node) {
224bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                    appendText(document, node, token, parser.getText());
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
2266bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes            } else if (token == XmlPullParser.TEXT || token == XmlPullParser.CDSECT) {
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                /*
2286bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes                 * Found a piece of text (possibly encoded as a CDATA section).
2296bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes                 * That's the easiest case. We simply take it and create a new text node,
2306bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes                 * or merge with an adjacent text node.
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 */
232bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                appendText(document, node, token, parser.getText());
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (token == XmlPullParser.ENTITY_REF) {
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                /*
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * Found an entity reference. If an entity resolver is
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * installed, we replace it by text (if possible). Otherwise we
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * add an entity reference node.
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 */
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String entity = parser.getName();
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (entityResolver != null) {
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // TODO Implement this...
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2450463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson                String resolved = resolvePredefinedOrCharacterEntity(entity);
2460463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson                if (resolved != null) {
2470463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson                    appendText(document, node, token, resolved);
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    node.appendChild(document.createEntityReference(entity));
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (token == XmlPullParser.START_TAG) {
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                /*
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * Found an element start tag. We create an element node with
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * the proper info and attributes. We then invoke parse()
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * recursively to handle the next level of nesting. When we
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * return from this call, we check that we are on the proper
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * element end tag. The whole handling differs somewhat
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 * depending on whether the parser is namespace-aware or not.
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 */
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (namespaceAware) {
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Collect info for element node
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    String namespace = parser.getNamespace();
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    String name = parser.getName();
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    String prefix = parser.getPrefix();
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if ("".equals(namespace)) {
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        namespace = null;
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
269f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Create element node and wire it correctly
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Element element = document.createElementNS(namespace, name);
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    element.setPrefix(prefix);
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    node.appendChild(element);
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    for (int i = 0; i < parser.getAttributeCount(); i++) {
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // Collect info for a single attribute node
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        String attrNamespace = parser.getAttributeNamespace(i);
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        String attrPrefix = parser.getAttributePrefix(i);
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        String attrName = parser.getAttributeName(i);
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        String attrValue = parser.getAttributeValue(i);
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if ("".equals(attrNamespace)) {
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            attrNamespace = null;
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
285f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // Create attribute node and wire it correctly
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        Attr attr = document.createAttributeNS(attrNamespace, attrName);
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        attr.setPrefix(attrPrefix);
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        attr.setValue(attrValue);
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        element.setAttributeNodeNS(attr);
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
292f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Recursive descent
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    token = parser.nextToken();
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    parse(parser, document, element, XmlPullParser.END_TAG);
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Expect the element's end tag here
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    parser.require(XmlPullParser.END_TAG, namespace, name);
299f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Collect info for element node
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    String name = parser.getName();
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Create element node and wire it correctly
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Element element = document.createElement(name);
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    node.appendChild(element);
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    for (int i = 0; i < parser.getAttributeCount(); i++) {
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // Collect info for a single attribute node
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        String attrName = parser.getAttributeName(i);
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        String attrValue = parser.getAttributeValue(i);
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // Create attribute node and wire it correctly
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        Attr attr = document.createAttribute(attrName);
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        attr.setValue(attrValue);
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        element.setAttributeNode(attr);
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Recursive descent
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    token = parser.nextToken();
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    parse(parser, document, element, XmlPullParser.END_TAG);
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Expect the element's end tag here
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    parser.require(XmlPullParser.END_TAG, "", name);
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            token = parser.nextToken();
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3326bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes    /**
333bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson     * @param token the XML pull parser token type, such as XmlPullParser.CDSECT
334bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson     *      or XmlPullParser.ENTITY_REF.
335f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     */
336bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    private void appendText(DocumentImpl document, Node parent, int token, String text) {
337af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes        // Ignore empty runs.
3380463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson        if (text.isEmpty()) {
339af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes            return;
340af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes        }
341af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes        // Merge with any previous text node if possible.
3420463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson        if (coalescing || token != XmlPullParser.CDSECT) {
343bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson            Node lastChild = parent.getLastChild();
3446bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes            if (lastChild != null && lastChild.getNodeType() == Node.TEXT_NODE) {
3456bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes                Text textNode = (Text) lastChild;
3465e60d541ae2a4085f4c6f3739c6cff84469bc052Jesse Wilson                textNode.appendData(text);
3476bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes                return;
3486bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes            }
349af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes        }
350af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes        // Okay, we really do need a new text node
351bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        parent.appendChild(token == XmlPullParser.CDSECT
352bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                ? new CDATASectionImpl(document, text)
353bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                : new TextImpl(document, text));
354af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes    }
355af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void setEntityResolver(EntityResolver resolver) {
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        entityResolver = resolver;
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void setErrorHandler(ErrorHandler handler) {
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        errorHandler = handler;
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Controls whether this DocumentBuilder ignores comments.
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void setIgnoreComments(boolean value) {
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ignoreComments = value;
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3736bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes    public void setCoalescing(boolean value) {
3746bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes        coalescing = value;
3756bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes    }
3766bcf32ab404c39b85d25430f6df16503ef3526cfElliott Hughes
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Controls whether this DocumentBuilder ignores element content whitespace.
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void setIgnoreElementContentWhitespace(boolean value) {
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ignoreElementContentWhitespace = value;
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Controls whether this DocumentBuilder is namespace-aware.
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void setNamespaceAware(boolean value) {
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        namespaceAware = value;
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
3920463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson     * Returns the replacement text or null if {@code entity} isn't predefined.
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
3940463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson    private String resolvePredefinedOrCharacterEntity(String entityName) {
395af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes        // Character references, section 4.1 of the XML specification.
3960463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson        if (entityName.startsWith("#x")) {
3970463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson            return resolveCharacterReference(entityName.substring(2), 16);
3980463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson        } else if (entityName.startsWith("#")) {
3990463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson            return resolveCharacterReference(entityName.substring(1), 10);
400af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes        }
401af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes        // Predefined entities, section 4.6 of the XML specification.
4020463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson        if ("lt".equals(entityName)) {
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return "<";
4040463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson        } else if ("gt".equals(entityName)) {
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return ">";
4060463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson        } else if ("amp".equals(entityName)) {
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return "&";
4080463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson        } else if ("apos".equals(entityName)) {
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return "'";
4100463b62eef5a7e8a477ddf7a972af198e46ecd5fJesse Wilson        } else if ("quot".equals(entityName)) {
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return "\"";
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
416af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes
417af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes    private String resolveCharacterReference(String value, int base) {
418af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes        try {
419af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes            int ch = Integer.parseInt(value, base);
420af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes            if (ch < 0 || ch > Character.MAX_VALUE) {
421af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes                return null;
422af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes            }
423f787a8787d0b7bcdc178ffc2e3343f1c1b02ed30Elliott Hughes            return String.valueOf((char) ch);
424af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes        } catch (NumberFormatException ex) {
425af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes            return null;
426af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes        }
427af74d493c2c90d9394ec75be6a9d2b9f62cb5e5fElliott Hughes    }
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
429