📄 xmlpullparser.java
字号:
/* 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. */package gr.fire.browser.util;import gr.fire.util.Log;import java.io.IOException;import java.io.Reader;import java.util.Hashtable;/** * A minimalistic XML pull parser, similar to kXML, but * not supporting namespaces or legacy events. If you need * support for namespaces, or access to XML comments or * processing instructions, please use kXML(2) instead. * */public class XmlPullParser{ static final private String UNEXPECTED_EOF = "Unexpected EOF"; /** * Return value of getType before first call to next() */ public static final int START_DOCUMENT = 0; /** * Signal logical end of xml document */ public static final int END_DOCUMENT = 1; /** * Start tag was just read */ public static final int START_TAG = 2; /** * End tag was just read */ public static final int END_TAG = 3; /** * Text was just read */ public static final int TEXT = 4; public static final int CDSECT = 5; public static final int ENTITY_REF = 6; public static final int LEGACY = 999; public static final Hashtable entityMap = new Hashtable(); static{ entityMap.put("amp", "&"); entityMap.put("apos", "'"); entityMap.put("gt", ">"); entityMap.put("lt", "<"); entityMap.put("quot", "\""); entityMap.put("nbsp", " "); entityMap.put("copy", "©"); entityMap.put("laquo", "«"); entityMap.put("raquo", "»"); entityMap.put("reg", "®"); } // general private boolean relaxed; private int depth; private String[] elementStack = new String[4]; // source private Reader reader; private boolean allowEntitiesInAttributes; private char[] srcBuf = new char[Runtime.getRuntime().freeMemory() >= 1048576 ? 8192 : 128]; private int srcPos; private int srcCount; private boolean eof; private int line; private int column; private int peek0; private int peek1; // txtbuffer private char[] txtBuf = new char[128]; private int txtPos; // Event-related private int type; private String text; private boolean isWhitespace; private String name; private boolean degenerated; private int attributeCount; private String[] attributes = new String[16]; private String[] TYPES = { "Start Document", "End Document", "Start Tag", "End Tag", "Text" }; private final int read() throws IOException { int r = this.peek0; this.peek0 = this.peek1; if (this.peek0 == -1) { this.eof = true; return r; } else if (r == '\n' || r == '\r') { this.line++; this.column = 0; if (r == '\r' && this.peek0 == '\n') this.peek0 = 0; } this.column++; if (this.srcPos >= this.srcCount) { this.srcCount = this.reader.read(this.srcBuf, 0, this.srcBuf.length); if (this.srcCount <= 0) { this.peek1 = -1; return r; } this.srcPos = 0; } this.peek1 = this.srcBuf[this.srcPos++]; return r; } private final void exception(String desc) throws IOException { throw new IOException(desc + " pos: " + getPositionDescription()); } private final void push(int c) { if (c == 0) return; if (this.txtPos == this.txtBuf.length) { char[] bigger = new char[this.txtPos * 4 / 3 + 4]; System.arraycopy(this.txtBuf, 0, bigger, 0, this.txtPos); this.txtBuf = bigger; } this.txtBuf[this.txtPos++] = (char) c; } private final void read(char c) throws IOException { if (read() != c) { if (this.relaxed) { if (c <= 32) { skip(); read(); } } else { exception("expected: '" + c + "'"); } } } private final void skip() throws IOException { while (!this.eof && this.peek0 <= ' ') read(); } private final String pop(int pos) { String result = new String(this.txtBuf, pos, this.txtPos - pos); this.txtPos = pos; return result; } private final String readName() throws IOException { int pos = this.txtPos; int c = this.peek0; if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c != '_' && c != ':' && !this.relaxed) exception("name expected"); do { push(read()); c = this.peek0; } while ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == ':' || c == '.'); return pop(pos); } private final void parseLegacy(boolean push) throws IOException { String req = ""; int term; read(); // < int c = read(); if (c == '?') { term = '?'; } else if (c == '!') { if (this.peek0 == '-') { req = "--"; term = '-'; } else { req = "DOCTYPE"; term = -1; } } else { if (c != '[') exception("cantreachme: " + c); req = "CDATA["; term = ']'; } for (int i = 0; i < req.length(); i++) read(req.charAt(i)); if (term == -1) parseDoctype(); else { while (true) { if (this.eof) exception(UNEXPECTED_EOF); c = read(); if (push) push(c); if ((term == '?' || c == term) && this.peek0 == term && this.peek1 == '>') break; } read(); read(); if (push && term != '?') pop(this.txtPos - 1); } } /** precondition: <! consumed */ private final void parseDoctype() throws IOException { int nesting = 1; while (true) { int i = read(); switch (i) { case -1: exception(UNEXPECTED_EOF); break; case '<': nesting++; break; case '>': if ((--nesting) == 0) return; break; } } } /* precondition: </ consumed */ private final void parseEndTag() throws IOException { read(); // '<' read(); // '/' this.name = readName(); if (this.depth == 0 && !this.relaxed) exception("element stack empty"); if (this.name.equals(this.elementStack[this.depth - 1])) this.depth--; else if (!this.relaxed) exception("expected: " + this.elementStack[this.depth]); skip(); read('>'); } private final int peekType() { switch (this.peek0) { case -1: return END_DOCUMENT; case '&': return ENTITY_REF; case '<': switch (this.peek1) { case '/': return END_TAG; case '[': return CDSECT; case '?': case '!': return LEGACY; default: return START_TAG; } default: return TEXT; } } private static 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; } /** Sets name and attributes */ private final void parseStartTag() throws IOException { read(); // < this.name = readName(); this.elementStack = ensureCapacity(this.elementStack, this.depth + 1); this.elementStack[this.depth++] = this.name; while (true) { skip(); int c = this.peek0; if (c == '/') { this.degenerated = true; read(); skip(); read('>'); break; } if (c == '>') { read(); break; } if (c == -1) exception(UNEXPECTED_EOF); String attrName = readName(); if (attrName.length() == 0) exception("attr name expected"); skip(); read('='); skip(); int delimiter = read(); if (delimiter != '\'' && delimiter != '"') {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -