1/*
2 * Copyright (C) 2007 Esmertec AG.
3 * Copyright (C) 2007 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.im.imps;
19
20import java.io.IOException;
21import java.io.InputStream;
22
23import org.xml.sax.Attributes;
24import org.xml.sax.ContentHandler;
25import org.xml.sax.InputSource;
26import org.xml.sax.SAXException;
27
28/*
29 * NOT thread-safe. Always use this in one thread.
30 */
31final class WbxmlParser {
32    private static final int BUFFER_SIZE = 1024;
33
34    private ContentHandler mContentHandler;
35    private int mNativeParser;
36    private AttributesImpl atts;
37
38    public WbxmlParser() {
39        atts = new AttributesImpl();
40        mNativeParser = nativeCreate("UTF-8");
41        if (mNativeParser == 0) {
42            throw new OutOfMemoryError();
43        }
44    }
45
46    @Override
47    protected void finalize() {
48        if (mNativeParser != 0) {
49            nativeRelease(mNativeParser);
50        }
51    }
52
53    public void setContentHandler(ContentHandler contentHandler) {
54        mContentHandler = contentHandler;
55    }
56
57    public void reset() {
58        if (mNativeParser != 0) {
59            nativeReset(mNativeParser);
60        }
61        atts.names = null;
62        atts.values = null;
63        mContentHandler = null;
64    }
65
66    public void parse(InputSource in) throws ParserException, SAXException, IOException {
67        InputStream byteStream = in.getByteStream();
68        byte[] buffer = new byte[BUFFER_SIZE];
69        int length;
70        // FIXME: nativeParse should throw ParserException but the dalvik
71        // seems to have problem throwing non-system exceptions from JNI
72        // code. Use IAE for now and file a bug report for this.
73        try {
74            while ((length = byteStream.read(buffer)) != -1) {
75                nativeParse(mNativeParser, buffer, length, false);
76            }
77            nativeParse(mNativeParser, new byte[1], 0, true);
78        } catch (IllegalArgumentException e) {
79            throw new ParserException(e);
80        }
81    }
82
83    void startElement(String name, String[] attrNames, String[] attrValues)
84            throws SAXException {
85        atts.names = attrNames;
86        atts.values = attrValues;
87        if(mContentHandler != null) {
88            mContentHandler.startElement("", name, name, atts);
89        }
90    }
91
92    void endElement(String name) throws SAXException {
93        if(mContentHandler != null) {
94            mContentHandler.endElement("", name, name);
95        }
96    }
97
98    void characters(char[] ch, int length) throws SAXException {
99        if(mContentHandler != null) {
100            mContentHandler.characters(ch, 0, length);
101        }
102    }
103
104    static native void nativeStaticInitialize();
105
106    native int nativeCreate(String encoding);
107
108    native void nativeRelease(int nativeParser);
109
110    native void nativeReset(int nativeParser);
111
112    // XXX: nativeParse should throw ParserException but the dalvik seems to
113    // have problem throwing non-system exceptions from JNI code. Use IAE
114    // for now and file a bug report for this.
115    native void nativeParse(int nativeParser, byte[] ch, int length,
116            boolean isEnd) throws IllegalArgumentException, SAXException, IOException;
117
118    static {
119        try {
120            System.loadLibrary("wbxml_jni");
121            nativeStaticInitialize();
122        } catch (UnsatisfiedLinkError ule) {
123            System.err.println("WARNING: Could not load library libwbxml_jni.so");
124        }
125    }
126
127    static class AttributesImpl implements Attributes {
128        String[] names = null;
129        String[] values = null;
130
131        public int getIndex(String qName) {
132            if(names == null) {
133                return -1;
134            }
135            for (int i = 0; i < names.length; i++) {
136                if (names[i].equals(qName)) {
137                    return i;
138                }
139            }
140            return -1;
141        }
142
143        public int getIndex(String uri, String localName) {
144            if(!"".equals(uri)) {
145                return -1;
146            }
147            return getIndex(localName);
148        }
149
150        public int getLength() {
151            return names == null ? 0 : names.length;
152        }
153
154        public String getLocalName(int index) {
155            if(index < 0 || index >= getLength()) {
156                return null;
157            }
158            return names[index];
159        }
160
161        public String getQName(int index) {
162            if(index < 0 || index >= getLength()) {
163                return null;
164            }
165            return names[index];
166        }
167
168        public String getType(int index) {
169            if(index < 0 || index >= getLength()) {
170                return null;
171            }
172            return "CDATA";
173        }
174
175        public String getType(String qName) {
176            return getIndex(qName) == -1 ? null : "CDATA";
177        }
178
179        public String getType(String uri, String localName) {
180            return getIndex(uri, localName) == -1 ? null : "CDATA";
181        }
182
183        public String getURI(int index) {
184            if(index < 0 || index >= getLength()) {
185                return null;
186            }
187            return "";
188        }
189
190        public String getValue(int index) {
191            if(index < 0 || index >= getLength()) {
192                return null;
193            }
194            return values[index];
195        }
196
197        public String getValue(String qName) {
198            int index = getIndex(qName);
199            return index == -1 ? null : values[index];
200        }
201
202        public String getValue(String uri, String localName) {
203            int index = getIndex(uri, localName);
204            return index == -1 ? null : values[index];
205        }
206    }
207}
208