auto import from //depot/cupcake/@135843
diff --git a/xml/src/main/java/org/kxml2/io/KXmlParser.java b/xml/src/main/java/org/kxml2/io/KXmlParser.java
new file mode 100644
index 0000000..0727bc7
--- /dev/null
+++ b/xml/src/main/java/org/kxml2/io/KXmlParser.java
@@ -0,0 +1,1440 @@
+/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE. */
+
+// Contributors: Paul Hackenberger (unterminated entity handling in relaxed mode)
+
+package org.kxml2.io;
+
+import java.io.*;
+import java.util.*;
+
+import org.xmlpull.v1.*;
+
+/** A simple, pull based XML parser. This classe replaces the kXML 1
+ XmlParser class and the corresponding event classes. */
+
+public class KXmlParser implements XmlPullParser {
+
+ private Object location;
+ static final private String UNEXPECTED_EOF = "Unexpected EOF";
+ static final private String ILLEGAL_TYPE = "Wrong event type";
+ static final private int LEGACY = 999;
+ static final private int XML_DECL = 998;
+
+ // general
+
+ private String version;
+ private Boolean standalone;
+
+ private boolean processNsp;
+ private boolean relaxed;
+ private Hashtable entityMap;
+ private int depth;
+ private String[] elementStack = new String[16];
+ private String[] nspStack = new String[8];
+ private int[] nspCounts = new int[4];
+
+ // source
+
+ private Reader reader;
+ private String encoding;
+ private char[] srcBuf;
+
+ private int srcPos;
+ private int srcCount;
+
+ private int line;
+ private int column;
+
+ // txtbuffer
+
+ private char[] txtBuf = new char[128];
+ private int txtPos;
+
+ // Event-related
+
+ private int type;
+ //private String text;
+ private boolean isWhitespace;
+ private String namespace;
+ private String prefix;
+ private String name;
+
+ private boolean degenerated;
+ private int attributeCount;
+ private String[] attributes = new String[16];
+ private int stackMismatch = 0;
+ private String error;
+
+ /**
+ * A separate peek buffer seems simpler than managing
+ * wrap around in the first level read buffer */
+
+ private int[] peek = new int[2];
+ private int peekCount;
+ private boolean wasCR;
+
+ private boolean unresolved;
+ private boolean token;
+
+ public KXmlParser() {
+ // BEGIN android-changed
+ // We don't have a Runtime class at this time.
+ // srcBuf =
+ // new char[Runtime.getRuntime().freeMemory() >= 1048576 ? 8192 : 128];
+ srcBuf = new char[8192];
+ // END android-changed
+ }
+
+ private final boolean isProp(String n1, boolean prop, String n2) {
+ if (!n1.startsWith("http://xmlpull.org/v1/doc/"))
+ return false;
+ if (prop)
+ return n1.substring(42).equals(n2);
+ else
+ return n1.substring(40).equals(n2);
+ }
+
+ private final boolean adjustNsp() throws XmlPullParserException {
+
+ boolean any = false;
+
+ for (int i = 0; i < attributeCount << 2; i += 4) {
+ // * 4 - 4; i >= 0; i -= 4) {
+
+ String attrName = attributes[i + 2];
+ int cut = attrName.indexOf(':');
+ String prefix;
+
+ if (cut != -1) {
+ prefix = attrName.substring(0, cut);
+ attrName = attrName.substring(cut + 1);
+ }
+ else if (attrName.equals("xmlns")) {
+ prefix = attrName;
+ attrName = null;
+ }
+ else
+ continue;
+
+ if (!prefix.equals("xmlns")) {
+ any = true;
+ }
+ else {
+ int j = (nspCounts[depth]++) << 1;
+
+ nspStack = ensureCapacity(nspStack, j + 2);
+ nspStack[j] = attrName;
+ nspStack[j + 1] = attributes[i + 3];
+
+ if (attrName != null && attributes[i + 3].equals(""))
+ error("illegal empty namespace");
+
+ // prefixMap = new PrefixMap (prefixMap, attrName, attr.getValue ());
+
+ //System.out.println (prefixMap);
+
+ System.arraycopy(
+ attributes,
+ i + 4,
+ attributes,
+ i,
+ ((--attributeCount) << 2) - i);
+
+ i -= 4;
+ }
+ }
+
+ if (any) {
+ for (int i = (attributeCount << 2) - 4; i >= 0; i -= 4) {
+
+ String attrName = attributes[i + 2];
+ int cut = attrName.indexOf(':');
+
+ if (cut == 0 && !relaxed)
+ throw new RuntimeException(
+ "illegal attribute name: " + attrName + " at " + this);
+
+ else if (cut != -1) {
+ String attrPrefix = attrName.substring(0, cut);
+
+ attrName = attrName.substring(cut + 1);
+
+ String attrNs = getNamespace(attrPrefix);
+
+ if (attrNs == null && !relaxed)
+ throw new RuntimeException(
+ "Undefined Prefix: " + attrPrefix + " in " + this);
+
+ attributes[i] = attrNs;
+ attributes[i + 1] = attrPrefix;
+ attributes[i + 2] = attrName;
+
+ /*
+ if (!relaxed) {
+ for (int j = (attributeCount << 2) - 4; j > i; j -= 4)
+ if (attrName.equals(attributes[j + 2])
+ && attrNs.equals(attributes[j]))
+ exception(
+ "Duplicate Attribute: {"
+ + attrNs
+ + "}"
+ + attrName);
+ }
+ */
+ }
+ }
+ }
+
+ int cut = name.indexOf(':');
+
+ if (cut == 0)
+ error("illegal tag name: " + name);
+
+ if (cut != -1) {
+ prefix = name.substring(0, cut);
+ name = name.substring(cut + 1);
+ }
+
+ this.namespace = getNamespace(prefix);
+
+ if (this.namespace == null) {
+ if (prefix != null)
+ error("undefined prefix: " + prefix);
+ this.namespace = NO_NAMESPACE;
+ }
+
+ return any;
+ }
+
+ private final String[] ensureCapacity(String[] arr, int required) {
+ if (arr.length >= required)
+ return arr;
+ String[] bigger = new String[required + 16];
+ System.arraycopy(arr, 0, bigger, 0, arr.length);
+ return bigger;
+ }
+
+ private final void error(String desc) throws XmlPullParserException {
+ if (relaxed) {
+ if (error == null)
+ error = "ERR: " + desc;
+ }
+ else
+ exception(desc);
+ }
+
+ private final void exception(String desc) throws XmlPullParserException {
+ throw new XmlPullParserException(
+ desc.length() < 100 ? desc : desc.substring(0, 100) + "\n",
+ this,
+ null);
+ }
+
+ /**
+ * common base for next and nextToken. Clears the state, except from
+ * txtPos and whitespace. Does not set the type variable */
+
+ private final void nextImpl() throws IOException, XmlPullParserException {
+
+ if (reader == null)
+ exception("No Input specified");
+
+ if (type == END_TAG)
+ depth--;
+
+ while (true) {
+ attributeCount = -1;
+
+ // degenerated needs to be handled before error because of possible
+ // processor expectations(!)
+
+ if (degenerated) {
+ degenerated = false;
+ type = END_TAG;
+ return;
+ }
+
+
+ if (error != null) {
+ for (int i = 0; i < error.length(); i++)
+ push(error.charAt(i));
+ // text = error;
+ error = null;
+ type = COMMENT;
+ return;
+ }
+
+
+ if (relaxed
+ && (stackMismatch > 0 || (peek(0) == -1 && depth > 0))) {
+ int sp = (depth - 1) << 2;
+ type = END_TAG;
+ namespace = elementStack[sp];
+ prefix = elementStack[sp + 1];
+ name = elementStack[sp + 2];
+ if (stackMismatch != 1)
+ error = "missing end tag /" + name + " inserted";
+ if (stackMismatch > 0)
+ stackMismatch--;
+ return;
+ }
+
+ prefix = null;
+ name = null;
+ namespace = null;
+ // text = null;
+
+ type = peekType();
+
+ switch (type) {
+
+ case ENTITY_REF :
+ pushEntity();
+ return;
+
+ case START_TAG :
+ parseStartTag(false);
+ return;
+
+ case END_TAG :
+ parseEndTag();
+ return;
+
+ case END_DOCUMENT :
+ return;
+
+ case TEXT :
+ pushText('<', !token);
+ if (depth == 0) {
+ if (isWhitespace)
+ type = IGNORABLE_WHITESPACE;
+ // make exception switchable for instances.chg... !!!!
+ // else
+ // exception ("text '"+getText ()+"' not allowed outside root element");
+ }
+ return;
+
+ default :
+ type = parseLegacy(token);
+ if (type != XML_DECL)
+ return;
+ }
+ }
+ }
+
+ private final int parseLegacy(boolean push)
+ throws IOException, XmlPullParserException {
+
+ String req = "";
+ int term;
+ int result;
+ int prev = 0;
+
+ read(); // <
+ int c = read();
+
+ if (c == '?') {
+ if ((peek(0) == 'x' || peek(0) == 'X')
+ && (peek(1) == 'm' || peek(1) == 'M')) {
+
+ if (push) {
+ push(peek(0));
+ push(peek(1));
+ }
+ read();
+ read();
+
+ if ((peek(0) == 'l' || peek(0) == 'L') && peek(1) <= ' ') {
+
+ if (line != 1 || column > 4)
+ error("PI must not start with xml");
+
+ parseStartTag(true);
+
+ if (attributeCount < 1 || !"version".equals(attributes[2]))
+ error("version expected");
+
+ version = attributes[3];
+
+ int pos = 1;
+
+ if (pos < attributeCount
+ && "encoding".equals(attributes[2 + 4])) {
+ encoding = attributes[3 + 4];
+ pos++;
+ }
+
+ if (pos < attributeCount
+ && "standalone".equals(attributes[4 * pos + 2])) {
+ String st = attributes[3 + 4 * pos];
+ if ("yes".equals(st))
+ standalone = new Boolean(true);
+ else if ("no".equals(st))
+ standalone = new Boolean(false);
+ else
+ error("illegal standalone value: " + st);
+ pos++;
+ }
+
+ if (pos != attributeCount)
+ error("illegal xmldecl");
+
+ isWhitespace = true;
+ txtPos = 0;
+
+ return XML_DECL;
+ }
+ }
+
+ /* int c0 = read ();
+ int c1 = read ();
+ int */
+
+ term = '?';
+ result = PROCESSING_INSTRUCTION;
+ }
+ else if (c == '!') {
+ if (peek(0) == '-') {
+ result = COMMENT;
+ req = "--";
+ term = '-';
+ }
+ else if (peek(0) == '[') {
+ result = CDSECT;
+ req = "[CDATA[";
+ term = ']';
+ push = true;
+ }
+ else {
+ result = DOCDECL;
+ req = "DOCTYPE";
+ term = -1;
+ }
+ }
+ else {
+ error("illegal: <" + c);
+ return COMMENT;
+ }
+
+ for (int i = 0; i < req.length(); i++)
+ read(req.charAt(i));
+
+ if (result == DOCDECL)
+ parseDoctype(push);
+ else {
+ while (true) {
+ c = read();
+ if (c == -1){
+ error(UNEXPECTED_EOF);
+ return COMMENT;
+ }
+
+ if (push)
+ push(c);
+
+ if ((term == '?' || c == term)
+ && peek(0) == term
+ && peek(1) == '>')
+ break;
+
+ prev = c;
+ }
+
+ if (term == '-' && prev == '-')
+ error("illegal comment delimiter: --->");
+
+ read();
+ read();
+
+ if (push && term != '?')
+ txtPos--;
+
+ }
+ return result;
+ }
+
+ /** precondition: <! consumed */
+
+ private final void parseDoctype(boolean push)
+ throws IOException, XmlPullParserException {
+
+ int nesting = 1;
+ boolean quoted = false;
+
+ // read();
+
+ while (true) {
+ int i = read();
+ switch (i) {
+
+ case -1 :
+ error(UNEXPECTED_EOF);
+ return;
+
+ case '\'' :
+ quoted = !quoted;
+ break;
+
+ case '<' :
+ if (!quoted)
+ nesting++;
+ break;
+
+ case '>' :
+ if (!quoted) {
+ if ((--nesting) == 0)
+ return;
+ }
+ break;
+ }
+ if (push)
+ push(i);
+ }
+ }
+
+ /* precondition: </ consumed */
+
+ private final void parseEndTag()
+ throws IOException, XmlPullParserException {
+
+ read(); // '<'
+ read(); // '/'
+ name = readName();
+ skip();
+ read('>');
+
+ int sp = (depth - 1) << 2;
+
+ if (depth == 0) {
+ error("element stack empty");
+ type = COMMENT;
+ return;
+ }
+
+ if (!name.equals(elementStack[sp + 3])) {
+ error("expected: /" + elementStack[sp + 3] + " read: " + name);
+
+ // become case insensitive in relaxed mode
+
+ int probe = sp;
+ while (probe >= 0 && !name.toLowerCase().equals(elementStack[probe + 3].toLowerCase())) {
+ stackMismatch++;
+ probe -= 4;
+ }
+
+ if (probe < 0) {
+ stackMismatch = 0;
+ // text = "unexpected end tag ignored";
+ type = COMMENT;
+ return;
+ }
+ }
+
+ namespace = elementStack[sp];
+ prefix = elementStack[sp + 1];
+ name = elementStack[sp + 2];
+ }
+
+ private final int peekType() throws IOException {
+ switch (peek(0)) {
+ case -1 :
+ return END_DOCUMENT;
+ case '&' :
+ return ENTITY_REF;
+ case '<' :
+ switch (peek(1)) {
+ case '/' :
+ return END_TAG;
+ case '?' :
+ case '!' :
+ return LEGACY;
+ default :
+ return START_TAG;
+ }
+ default :
+ return TEXT;
+ }
+ }
+
+ private final String get(int pos) {
+ return new String(txtBuf, pos, txtPos - pos);
+ }
+
+ /*
+ private final String pop (int pos) {
+ String result = new String (txtBuf, pos, txtPos - pos);
+ txtPos = pos;
+ return result;
+ }
+ */
+
+ private final void push(int c) {
+
+ isWhitespace &= c <= ' ';
+
+ if (txtPos == txtBuf.length) {
+ char[] bigger = new char[txtPos * 4 / 3 + 4];
+ System.arraycopy(txtBuf, 0, bigger, 0, txtPos);
+ txtBuf = bigger;
+ }
+
+ txtBuf[txtPos++] = (char) c;
+ }
+
+ /** Sets name and attributes */
+
+ private final void parseStartTag(boolean xmldecl)
+ throws IOException, XmlPullParserException {
+
+ if (!xmldecl)
+ read();
+ name = readName();
+ attributeCount = 0;
+
+ while (true) {
+ skip();
+
+ int c = peek(0);
+
+ if (xmldecl) {
+ if (c == '?') {
+ read();
+ read('>');
+ return;
+ }
+ }
+ else {
+ if (c == '/') {
+ degenerated = true;
+ read();
+ skip();
+ read('>');
+ break;
+ }
+
+ if (c == '>' && !xmldecl) {
+ read();
+ break;
+ }
+ }
+
+ if (c == -1) {
+ error(UNEXPECTED_EOF);
+ //type = COMMENT;
+ return;
+ }
+
+ String attrName = readName();
+
+ if (attrName.length() == 0) {
+ error("attr name expected");
+ //type = COMMENT;
+ break;
+ }
+
+ int i = (attributeCount++) << 2;
+
+ attributes = ensureCapacity(attributes, i + 4);
+
+ attributes[i++] = "";
+ attributes[i++] = null;
+ attributes[i++] = attrName;
+
+ skip();
+
+ if (peek(0) != '=') {
+ error("Attr.value missing f. "+attrName);
+ attributes[i] = "1";
+ }
+ else {
+ read('=');
+ skip();
+ int delimiter = peek(0);
+
+ if (delimiter != '\'' && delimiter != '"') {
+ error("attr value delimiter missing!");
+ delimiter = ' ';
+ }
+ else
+ read();
+
+ int p = txtPos;
+ pushText(delimiter, true);
+
+ attributes[i] = get(p);
+ txtPos = p;
+
+ if (delimiter != ' ')
+ read(); // skip endquote
+ }
+ }
+
+ int sp = depth++ << 2;
+
+ elementStack = ensureCapacity(elementStack, sp + 4);
+ elementStack[sp + 3] = name;
+
+ if (depth >= nspCounts.length) {
+ int[] bigger = new int[depth + 4];
+ System.arraycopy(nspCounts, 0, bigger, 0, nspCounts.length);
+ nspCounts = bigger;
+ }
+
+ nspCounts[depth] = nspCounts[depth - 1];
+
+ /*
+ if(!relaxed){
+ for (int i = attributeCount - 1; i > 0; i--) {
+ for (int j = 0; j < i; j++) {
+ if (getAttributeName(i).equals(getAttributeName(j)))
+ exception("Duplicate Attribute: " + getAttributeName(i));
+ }
+ }
+ }
+ */
+ if (processNsp)
+ adjustNsp();
+ else
+ namespace = "";
+
+ elementStack[sp] = namespace;
+ elementStack[sp + 1] = prefix;
+ elementStack[sp + 2] = name;
+ }
+
+ /**
+ * result: isWhitespace; if the setName parameter is set,
+ * the name of the entity is stored in "name" */
+
+ private final void pushEntity()
+ throws IOException, XmlPullParserException {
+
+ push(read()); // &
+
+
+ int pos = txtPos;
+
+ while (true) {
+ int c = read();
+ if (c == ';')
+ break;
+ if (c < 128
+ && (c < '0' || c > '9')
+ && (c < 'a' || c > 'z')
+ && (c < 'A' || c > 'Z')
+ && c != '_'
+ && c != '-'
+ && c != '#') {
+ if(!relaxed){
+ error("unterminated entity ref");
+ }
+ //; ends with:"+(char)c);
+ if (c != -1)
+ push(c);
+ return;
+ }
+
+ push(c);
+ }
+
+ String code = get(pos);
+ txtPos = pos - 1;
+ if (token && type == ENTITY_REF){
+ name = code;
+ }
+
+ if (code.charAt(0) == '#') {
+ int c =
+ (code.charAt(1) == 'x'
+ ? Integer.parseInt(code.substring(2), 16)
+ : Integer.parseInt(code.substring(1)));
+ push(c);
+ return;
+ }
+
+ String result = (String) entityMap.get(code);
+
+ unresolved = result == null;
+
+ if (unresolved) {
+ if (!token)
+ error("unresolved: &" + code + ";");
+ }
+ else {
+ for (int i = 0; i < result.length(); i++)
+ push(result.charAt(i));
+ }
+ }
+
+ /** types:
+ '<': parse to any token (for nextToken ())
+ '"': parse to quote
+ ' ': parse to whitespace or '>'
+ */
+
+ private final void pushText(int delimiter, boolean resolveEntities)
+ throws IOException, XmlPullParserException {
+
+ int next = peek(0);
+ int cbrCount = 0;
+
+ while (next != -1 && next != delimiter) { // covers eof, '<', '"'
+
+ if (delimiter == ' ')
+ if (next <= ' ' || next == '>')
+ break;
+
+ if (next == '&') {
+ if (!resolveEntities)
+ break;
+
+ pushEntity();
+ }
+ else if (next == '\n' && type == START_TAG) {
+ read();
+ push(' ');
+ }
+ else
+ push(read());
+
+ if (next == '>' && cbrCount >= 2 && delimiter != ']')
+ error("Illegal: ]]>");
+
+ if (next == ']')
+ cbrCount++;
+ else
+ cbrCount = 0;
+
+ next = peek(0);
+ }
+ }
+
+ private final void read(char c)
+ throws IOException, XmlPullParserException {
+ int a = read();
+ if (a != c)
+ error("expected: '" + c + "' actual: '" + ((char) a) + "'");
+ }
+
+ private final int read() throws IOException {
+ int result;
+
+ if (peekCount == 0)
+ result = peek(0);
+ else {
+ result = peek[0];
+ peek[0] = peek[1];
+ }
+ // else {
+ // result = peek[0];
+ // System.arraycopy (peek, 1, peek, 0, peekCount-1);
+ // }
+ peekCount--;
+
+ column++;
+
+ if (result == '\n') {
+
+ line++;
+ column = 1;
+ }
+
+ return result;
+ }
+
+ /** Does never read more than needed */
+
+ private final int peek(int pos) throws IOException {
+
+ while (pos >= peekCount) {
+
+ int nw;
+
+ if (srcBuf.length <= 1)
+ nw = reader.read();
+ else if (srcPos < srcCount)
+ nw = srcBuf[srcPos++];
+ else {
+ srcCount = reader.read(srcBuf, 0, srcBuf.length);
+ if (srcCount <= 0)
+ nw = -1;
+ else
+ nw = srcBuf[0];
+
+ srcPos = 1;
+ }
+
+ if (nw == '\r') {
+ wasCR = true;
+ peek[peekCount++] = '\n';
+ }
+ else {
+ if (nw == '\n') {
+ if (!wasCR)
+ peek[peekCount++] = '\n';
+ }
+ else
+ peek[peekCount++] = nw;
+
+ wasCR = false;
+ }
+ }
+
+ return peek[pos];
+ }
+
+ private final String readName()
+ throws IOException, XmlPullParserException {
+
+ int pos = txtPos;
+ int c = peek(0);
+ if ((c < 'a' || c > 'z')
+ && (c < 'A' || c > 'Z')
+ && c != '_'
+ && c != ':'
+ && c < 0x0c0
+ && !relaxed)
+ error("name expected");
+
+ do {
+ push(read());
+ c = peek(0);
+ }
+ while ((c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9')
+ || c == '_'
+ || c == '-'
+ || c == ':'
+ || c == '.'
+ || c >= 0x0b7);
+
+ String result = get(pos);
+ txtPos = pos;
+ return result;
+ }
+
+ private final void skip() throws IOException {
+
+ while (true) {
+ int c = peek(0);
+ if (c > ' ' || c == -1)
+ break;
+ read();
+ }
+ }
+
+ // public part starts here...
+
+ public void setInput(Reader reader) throws XmlPullParserException {
+ this.reader = reader;
+
+ line = 1;
+ column = 0;
+ type = START_DOCUMENT;
+ name = null;
+ namespace = null;
+ degenerated = false;
+ attributeCount = -1;
+ encoding = null;
+ version = null;
+ standalone = null;
+
+ if (reader == null)
+ return;
+
+ srcPos = 0;
+ srcCount = 0;
+ peekCount = 0;
+ depth = 0;
+
+ entityMap = new Hashtable();
+ entityMap.put("amp", "&");
+ entityMap.put("apos", "'");
+ entityMap.put("gt", ">");
+ entityMap.put("lt", "<");
+ entityMap.put("quot", "\"");
+ }
+
+ public void setInput(InputStream is, String _enc)
+ throws XmlPullParserException {
+
+ srcPos = 0;
+ srcCount = 0;
+ String enc = _enc;
+
+ if (is == null)
+ throw new IllegalArgumentException();
+
+ try {
+
+ if (enc == null) {
+ // read four bytes
+
+ int chk = 0;
+
+ while (srcCount < 4) {
+ int i = is.read();
+ if (i == -1)
+ break;
+ chk = (chk << 8) | i;
+ srcBuf[srcCount++] = (char) i;
+ }
+
+ if (srcCount == 4) {
+ switch (chk) {
+ case 0x00000FEFF :
+ enc = "UTF-32BE";
+ srcCount = 0;
+ break;
+
+ case 0x0FFFE0000 :
+ enc = "UTF-32LE";
+ srcCount = 0;
+ break;
+
+ case 0x03c :
+ enc = "UTF-32BE";
+ srcBuf[0] = '<';
+ srcCount = 1;
+ break;
+
+ case 0x03c000000 :
+ enc = "UTF-32LE";
+ srcBuf[0] = '<';
+ srcCount = 1;
+ break;
+
+ case 0x0003c003f :
+ enc = "UTF-16BE";
+ srcBuf[0] = '<';
+ srcBuf[1] = '?';
+ srcCount = 2;
+ break;
+
+ case 0x03c003f00 :
+ enc = "UTF-16LE";
+ srcBuf[0] = '<';
+ srcBuf[1] = '?';
+ srcCount = 2;
+ break;
+
+ case 0x03c3f786d :
+ while (true) {
+ int i = is.read();
+ if (i == -1)
+ break;
+ srcBuf[srcCount++] = (char) i;
+ if (i == '>') {
+ String s = new String(srcBuf, 0, srcCount);
+ int i0 = s.indexOf("encoding");
+ if (i0 != -1) {
+ while (s.charAt(i0) != '"'
+ && s.charAt(i0) != '\'')
+ i0++;
+ char deli = s.charAt(i0++);
+ int i1 = s.indexOf(deli, i0);
+ enc = s.substring(i0, i1);
+ }
+ break;
+ }
+ }
+
+ default :
+ if ((chk & 0x0ffff0000) == 0x0FEFF0000) {
+ enc = "UTF-16BE";
+ srcBuf[0] =
+ (char) ((srcBuf[2] << 8) | srcBuf[3]);
+ srcCount = 1;
+ }
+ else if ((chk & 0x0ffff0000) == 0x0fffe0000) {
+ enc = "UTF-16LE";
+ srcBuf[0] =
+ (char) ((srcBuf[3] << 8) | srcBuf[2]);
+ srcCount = 1;
+ }
+ else if ((chk & 0x0ffffff00) == 0x0EFBBBF00) {
+ enc = "UTF-8";
+ srcBuf[0] = srcBuf[3];
+ srcCount = 1;
+ }
+ }
+ }
+ }
+
+ if (enc == null)
+ enc = "UTF-8";
+
+ int sc = srcCount;
+ setInput(new InputStreamReader(is, enc));
+ encoding = _enc;
+ srcCount = sc;
+ }
+ catch (Exception e) {
+ throw new XmlPullParserException(
+ "Invalid stream or encoding: " + e.toString(),
+ this,
+ e);
+ }
+ }
+
+ public boolean getFeature(String feature) {
+ if (XmlPullParser.FEATURE_PROCESS_NAMESPACES.equals(feature))
+ return processNsp;
+ else if (isProp(feature, false, "relaxed"))
+ return relaxed;
+ else
+ return false;
+ }
+
+ public String getInputEncoding() {
+ return encoding;
+ }
+
+ public void defineEntityReplacementText(String entity, String value)
+ throws XmlPullParserException {
+ if (entityMap == null)
+ throw new RuntimeException("entity replacement text must be defined after setInput!");
+ entityMap.put(entity, value);
+ }
+
+ public Object getProperty(String property) {
+ if (isProp(property, true, "xmldecl-version"))
+ return version;
+ if (isProp(property, true, "xmldecl-standalone"))
+ return standalone;
+ if (isProp(property, true, "location"))
+ return location != null ? location : reader.toString();
+ return null;
+ }
+
+ public int getNamespaceCount(int depth) {
+ if (depth > this.depth)
+ throw new IndexOutOfBoundsException();
+ return nspCounts[depth];
+ }
+
+ public String getNamespacePrefix(int pos) {
+ return nspStack[pos << 1];
+ }
+
+ public String getNamespaceUri(int pos) {
+ return nspStack[(pos << 1) + 1];
+ }
+
+ public String getNamespace(String prefix) {
+
+ if ("xml".equals(prefix))
+ return "http://www.w3.org/XML/1998/namespace";
+ if ("xmlns".equals(prefix))
+ return "http://www.w3.org/2000/xmlns/";
+
+ for (int i = (getNamespaceCount(depth) << 1) - 2; i >= 0; i -= 2) {
+ if (prefix == null) {
+ if (nspStack[i] == null)
+ return nspStack[i + 1];
+ }
+ else if (prefix.equals(nspStack[i]))
+ return nspStack[i + 1];
+ }
+ return null;
+ }
+
+ public int getDepth() {
+ return depth;
+ }
+
+ public String getPositionDescription() {
+
+ StringBuffer buf =
+ new StringBuffer(type < TYPES.length ? TYPES[type] : "unknown");
+ buf.append(' ');
+
+ if (type == START_TAG || type == END_TAG) {
+ if (degenerated)
+ buf.append("(empty) ");
+ buf.append('<');
+ if (type == END_TAG)
+ buf.append('/');
+
+ if (prefix != null)
+ buf.append("{" + namespace + "}" + prefix + ":");
+ buf.append(name);
+
+ int cnt = attributeCount << 2;
+ for (int i = 0; i < cnt; i += 4) {
+ buf.append(' ');
+ if (attributes[i + 1] != null)
+ buf.append(
+ "{" + attributes[i] + "}" + attributes[i + 1] + ":");
+ buf.append(attributes[i + 2] + "='" + attributes[i + 3] + "'");
+ }
+
+ buf.append('>');
+ }
+ else if (type == IGNORABLE_WHITESPACE);
+ else if (type != TEXT)
+ buf.append(getText());
+ else if (isWhitespace)
+ buf.append("(whitespace)");
+ else {
+ String text = getText();
+ if (text.length() > 16)
+ text = text.substring(0, 16) + "...";
+ buf.append(text);
+ }
+
+ buf.append("@"+line + ":" + column);
+ if(location != null){
+ buf.append(" in ");
+ buf.append(location);
+ }
+ else if(reader != null){
+ buf.append(" in ");
+ buf.append(reader.toString());
+ }
+ return buf.toString();
+ }
+
+ public int getLineNumber() {
+ return line;
+ }
+
+ public int getColumnNumber() {
+ return column;
+ }
+
+ public boolean isWhitespace() throws XmlPullParserException {
+ if (type != TEXT && type != IGNORABLE_WHITESPACE && type != CDSECT)
+ exception(ILLEGAL_TYPE);
+ return isWhitespace;
+ }
+
+ public String getText() {
+ return type < TEXT
+ || (type == ENTITY_REF && unresolved) ? null : get(0);
+ }
+
+ public char[] getTextCharacters(int[] poslen) {
+ if (type >= TEXT) {
+ if (type == ENTITY_REF) {
+ poslen[0] = 0;
+ poslen[1] = name.length();
+ return name.toCharArray();
+ }
+ poslen[0] = 0;
+ poslen[1] = txtPos;
+ return txtBuf;
+ }
+
+ poslen[0] = -1;
+ poslen[1] = -1;
+ return null;
+ }
+
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public boolean isEmptyElementTag() throws XmlPullParserException {
+ if (type != START_TAG)
+ exception(ILLEGAL_TYPE);
+ return degenerated;
+ }
+
+ public int getAttributeCount() {
+ return attributeCount;
+ }
+
+ public String getAttributeType(int index) {
+ return "CDATA";
+ }
+
+ public boolean isAttributeDefault(int index) {
+ return false;
+ }
+
+ public String getAttributeNamespace(int index) {
+ if (index >= attributeCount)
+ throw new IndexOutOfBoundsException();
+ return attributes[index << 2];
+ }
+
+ public String getAttributeName(int index) {
+ if (index >= attributeCount)
+ throw new IndexOutOfBoundsException();
+ return attributes[(index << 2) + 2];
+ }
+
+ public String getAttributePrefix(int index) {
+ if (index >= attributeCount)
+ throw new IndexOutOfBoundsException();
+ return attributes[(index << 2) + 1];
+ }
+
+ public String getAttributeValue(int index) {
+ if (index >= attributeCount)
+ throw new IndexOutOfBoundsException();
+ return attributes[(index << 2) + 3];
+ }
+
+ public String getAttributeValue(String namespace, String name) {
+
+ for (int i = (attributeCount << 2) - 4; i >= 0; i -= 4) {
+ if (attributes[i + 2].equals(name)
+ && (namespace == null || attributes[i].equals(namespace)))
+ return attributes[i + 3];
+ }
+
+ return null;
+ }
+
+ public int getEventType() throws XmlPullParserException {
+ return type;
+ }
+
+ public int next() throws XmlPullParserException, IOException {
+
+ txtPos = 0;
+ isWhitespace = true;
+ int minType = 9999;
+ token = false;
+
+ do {
+ nextImpl();
+ if (type < minType)
+ minType = type;
+ // if (curr <= TEXT) type = curr;
+ }
+ while (minType > ENTITY_REF // ignorable
+ || (minType >= TEXT && peekType() >= TEXT));
+
+ type = minType;
+ if (type > TEXT)
+ type = TEXT;
+
+ return type;
+ }
+
+ public int nextToken() throws XmlPullParserException, IOException {
+
+ isWhitespace = true;
+ txtPos = 0;
+
+ token = true;
+ nextImpl();
+ return type;
+ }
+
+ //
+ // utility methods to make XML parsing easier ...
+
+ public int nextTag() throws XmlPullParserException, IOException {
+
+ next();
+ if (type == TEXT && isWhitespace)
+ next();
+
+ if (type != END_TAG && type != START_TAG)
+ exception("unexpected type");
+
+ return type;
+ }
+
+ public void require(int type, String namespace, String name)
+ throws XmlPullParserException, IOException {
+
+ if (type != this.type
+ || (namespace != null && !namespace.equals(getNamespace()))
+ || (name != null && !name.equals(getName())))
+ exception(
+ "expected: " + TYPES[type] + " {" + namespace + "}" + name);
+ }
+
+ public String nextText() throws XmlPullParserException, IOException {
+ if (type != START_TAG)
+ exception("precondition: START_TAG");
+
+ next();
+
+ String result;
+
+ if (type == TEXT) {
+ result = getText();
+ next();
+ }
+ else
+ result = "";
+
+ if (type != END_TAG)
+ exception("END_TAG expected");
+
+ return result;
+ }
+
+ public void setFeature(String feature, boolean value)
+ throws XmlPullParserException {
+ if (XmlPullParser.FEATURE_PROCESS_NAMESPACES.equals(feature))
+ processNsp = value;
+ else if (isProp(feature, false, "relaxed"))
+ relaxed = value;
+ else
+ exception("unsupported feature: " + feature);
+ }
+
+ public void setProperty(String property, Object value)
+ throws XmlPullParserException {
+ if(isProp(property, true, "location"))
+ location = value;
+ else
+ throw new XmlPullParserException("unsupported property: " + property);
+ }
+
+ /**
+ * Skip sub tree that is currently porser positioned on.
+ * <br>NOTE: parser must be on START_TAG and when funtion returns
+ * parser will be positioned on corresponding END_TAG.
+ */
+
+ // Implementation copied from Alek's mail...
+
+ public void skipSubTree() throws XmlPullParserException, IOException {
+ require(START_TAG, null, null);
+ int level = 1;
+ while (level > 0) {
+ int eventType = next();
+ if (eventType == END_TAG) {
+ --level;
+ }
+ else if (eventType == START_TAG) {
+ ++level;
+ }
+ }
+ }
+}