diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | fdb2704414a9ed92394ada0d1395e4db86889465 (patch) | |
tree | 9b591a4a50054274a197f02b3ccb51313681879f /xml/src/main/java/org/kxml2 | |
download | libcore-fdb2704414a9ed92394ada0d1395e4db86889465.zip libcore-fdb2704414a9ed92394ada0d1395e4db86889465.tar.gz libcore-fdb2704414a9ed92394ada0d1395e4db86889465.tar.bz2 |
Initial Contribution
Diffstat (limited to 'xml/src/main/java/org/kxml2')
-rw-r--r-- | xml/src/main/java/org/kxml2/io/KXmlParser.java | 1438 | ||||
-rw-r--r-- | xml/src/main/java/org/kxml2/io/KXmlSerializer.java | 562 | ||||
-rw-r--r-- | xml/src/main/java/org/kxml2/kdom/Document.java | 129 | ||||
-rw-r--r-- | xml/src/main/java/org/kxml2/kdom/Element.java | 336 | ||||
-rw-r--r-- | xml/src/main/java/org/kxml2/kdom/Node.java | 366 | ||||
-rw-r--r-- | xml/src/main/java/org/kxml2/wap/Wbxml.java | 49 | ||||
-rw-r--r-- | xml/src/main/java/org/kxml2/wap/WbxmlParser.java | 1050 | ||||
-rw-r--r-- | xml/src/main/java/org/kxml2/wap/WbxmlSerializer.java | 418 | ||||
-rw-r--r-- | xml/src/main/java/org/kxml2/wap/syncml/SyncML.java | 192 | ||||
-rw-r--r-- | xml/src/main/java/org/kxml2/wap/wml/Wml.java | 233 | ||||
-rw-r--r-- | xml/src/main/java/org/kxml2/wap/wv/WV.java | 593 |
11 files changed, 5366 insertions, 0 deletions
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..8125745 --- /dev/null +++ b/xml/src/main/java/org/kxml2/io/KXmlParser.java @@ -0,0 +1,1438 @@ +/* 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 HashMap 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() { +// srcBuf = new char[Runtime.getRuntime().freeMemory() >= 1048576 ? 8192 : 128]; + + // XXX: We don't have a Runtime class at this time. + srcBuf = new char[8192]; + } + + 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 HashMap(); + 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; + } + } + } +} diff --git a/xml/src/main/java/org/kxml2/io/KXmlSerializer.java b/xml/src/main/java/org/kxml2/io/KXmlSerializer.java new file mode 100644 index 0000000..d63ed04 --- /dev/null +++ b/xml/src/main/java/org/kxml2/io/KXmlSerializer.java @@ -0,0 +1,562 @@ +/* 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 org.kxml2.io; + +import java.io.*; +import org.xmlpull.v1.*; + +public class KXmlSerializer implements XmlSerializer { + + // static final String UNDEFINED = ":"; + + // BEGIN android-added + /** size (in characters) for the write buffer */ + private static final int WRITE_BUFFER_SIZE = 500; + // END android-added + + // BEGIN android-changed + // (Guarantee that the writer is always buffered.) + private BufferedWriter writer; + // END android-changed + + private boolean pending; + private int auto; + private int depth; + + private String[] elementStack = new String[12]; + //nsp/prefix/name + private int[] nspCounts = new int[4]; + private String[] nspStack = new String[8]; + //prefix/nsp; both empty are "" + private boolean[] indent = new boolean[4]; + private boolean unicode; + private String encoding; + + private final void check(boolean close) throws IOException { + if (!pending) + return; + + depth++; + pending = false; + + if (indent.length <= depth) { + boolean[] hlp = new boolean[depth + 4]; + System.arraycopy(indent, 0, hlp, 0, depth); + indent = hlp; + } + indent[depth] = indent[depth - 1]; + + for (int i = nspCounts[depth - 1]; + i < nspCounts[depth]; + i++) { + writer.write(' '); + writer.write("xmlns"); + if (!"".equals(nspStack[i * 2])) { + writer.write(':'); + writer.write(nspStack[i * 2]); + } + else if ("".equals(getNamespace()) && !"".equals(nspStack[i * 2 + 1])) + throw new IllegalStateException("Cannot set default namespace for elements in no namespace"); + writer.write("=\""); + writeEscaped(nspStack[i * 2 + 1], '"'); + writer.write('"'); + } + + if (nspCounts.length <= depth + 1) { + int[] hlp = new int[depth + 8]; + System.arraycopy(nspCounts, 0, hlp, 0, depth + 1); + nspCounts = hlp; + } + + nspCounts[depth + 1] = nspCounts[depth]; + // nspCounts[depth + 2] = nspCounts[depth]; + + writer.write(close ? " />" : ">"); + } + + private final void writeEscaped(String s, int quot) + throws IOException { + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + switch (c) { + case '\n': + case '\r': + case '\t': + if(quot == -1) + writer.write(c); + else + writer.write("&#"+((int) c)+';'); + break; + case '&' : + writer.write("&"); + break; + case '>' : + writer.write(">"); + break; + case '<' : + writer.write("<"); + break; + case '"' : + case '\'' : + if (c == quot) { + writer.write( + c == '"' ? """ : "'"); + break; + } + default : + //if(c < ' ') + // throw new IllegalArgumentException("Illegal control code:"+((int) c)); + + if (c >= ' ' && c !='@' && (c < 127 || unicode)) + writer.write(c); + else + writer.write("&#" + ((int) c) + ";"); + + } + } + } + + /* + private final void writeIndent() throws IOException { + writer.write("\r\n"); + for (int i = 0; i < depth; i++) + writer.write(' '); + }*/ + + public void docdecl(String dd) throws IOException { + writer.write("<!DOCTYPE"); + writer.write(dd); + writer.write(">"); + } + + public void endDocument() throws IOException { + while (depth > 0) { + endTag( + elementStack[depth * 3 - 3], + elementStack[depth * 3 - 1]); + } + flush(); + } + + public void entityRef(String name) throws IOException { + check(false); + writer.write('&'); + writer.write(name); + writer.write(';'); + } + + public boolean getFeature(String name) { + //return false; + return ( + "http://xmlpull.org/v1/doc/features.html#indent-output" + .equals( + name)) + ? indent[depth] + : false; + } + + public String getPrefix(String namespace, boolean create) { + try { + return getPrefix(namespace, false, create); + } + catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + private final String getPrefix( + String namespace, + boolean includeDefault, + boolean create) + throws IOException { + + for (int i = nspCounts[depth + 1] * 2 - 2; + i >= 0; + i -= 2) { + if (nspStack[i + 1].equals(namespace) + && (includeDefault || !nspStack[i].equals(""))) { + String cand = nspStack[i]; + for (int j = i + 2; + j < nspCounts[depth + 1] * 2; + j++) { + if (nspStack[j].equals(cand)) { + cand = null; + break; + } + } + if (cand != null) + return cand; + } + } + + if (!create) + return null; + + String prefix; + + if ("".equals(namespace)) + prefix = ""; + else { + do { + prefix = "n" + (auto++); + for (int i = nspCounts[depth + 1] * 2 - 2; + i >= 0; + i -= 2) { + if (prefix.equals(nspStack[i])) { + prefix = null; + break; + } + } + } + while (prefix == null); + } + + boolean p = pending; + pending = false; + setPrefix(prefix, namespace); + pending = p; + return prefix; + } + + public Object getProperty(String name) { + throw new RuntimeException("Unsupported property"); + } + + public void ignorableWhitespace(String s) + throws IOException { + text(s); + } + + public void setFeature(String name, boolean value) { + if ("http://xmlpull.org/v1/doc/features.html#indent-output" + .equals(name)) { + indent[depth] = value; + } + else + throw new RuntimeException("Unsupported Feature"); + } + + public void setProperty(String name, Object value) { + throw new RuntimeException( + "Unsupported Property:" + value); + } + + public void setPrefix(String prefix, String namespace) + throws IOException { + + check(false); + if (prefix == null) + prefix = ""; + if (namespace == null) + namespace = ""; + + String defined = getPrefix(namespace, true, false); + + // boil out if already defined + + if (prefix.equals(defined)) + return; + + int pos = (nspCounts[depth + 1]++) << 1; + + if (nspStack.length < pos + 1) { + String[] hlp = new String[nspStack.length + 16]; + System.arraycopy(nspStack, 0, hlp, 0, pos); + nspStack = hlp; + } + + nspStack[pos++] = prefix; + nspStack[pos] = namespace; + } + + public void setOutput(Writer writer) { + // BEGIN android-changed + // Guarantee that the writer is always buffered. + if (writer instanceof BufferedWriter) { + this.writer = (BufferedWriter) writer; + } else { + this.writer = new BufferedWriter(writer, WRITE_BUFFER_SIZE); + } + // END android-changed + + // elementStack = new String[12]; //nsp/prefix/name + //nspCounts = new int[4]; + //nspStack = new String[8]; //prefix/nsp + //indent = new boolean[4]; + + nspCounts[0] = 2; + nspCounts[1] = 2; + nspStack[0] = ""; + nspStack[1] = ""; + nspStack[2] = "xml"; + nspStack[3] = "http://www.w3.org/XML/1998/namespace"; + pending = false; + auto = 0; + depth = 0; + + unicode = false; + } + + public void setOutput(OutputStream os, String encoding) + throws IOException { + if (os == null) + throw new IllegalArgumentException(); + setOutput( + encoding == null + ? new OutputStreamWriter(os) + : new OutputStreamWriter(os, encoding)); + this.encoding = encoding; + if (encoding != null + && encoding.toLowerCase().startsWith("utf")) + unicode = true; + } + + public void startDocument( + String encoding, + Boolean standalone) + throws IOException { + writer.write("<?xml version='1.0' "); + + if (encoding != null) { + this.encoding = encoding; + if (encoding.toLowerCase().startsWith("utf")) + unicode = true; + } + + if (this.encoding != null) { + writer.write("encoding='"); + writer.write(this.encoding); + writer.write("' "); + } + + if (standalone != null) { + writer.write("standalone='"); + writer.write( + standalone.booleanValue() ? "yes" : "no"); + writer.write("' "); + } + writer.write("?>"); + } + + public XmlSerializer startTag(String namespace, String name) + throws IOException { + check(false); + + // if (namespace == null) + // namespace = ""; + + if (indent[depth]) { + writer.write("\r\n"); + for (int i = 0; i < depth; i++) + writer.write(" "); + } + + int esp = depth * 3; + + if (elementStack.length < esp + 3) { + String[] hlp = new String[elementStack.length + 12]; + System.arraycopy(elementStack, 0, hlp, 0, esp); + elementStack = hlp; + } + + String prefix = + namespace == null + ? "" + : getPrefix(namespace, true, true); + + if ("".equals(namespace)) { + for (int i = nspCounts[depth]; + i < nspCounts[depth + 1]; + i++) { + if ("".equals(nspStack[i * 2]) && !"".equals(nspStack[i * 2 + 1])) { + throw new IllegalStateException("Cannot set default namespace for elements in no namespace"); + } + } + } + + elementStack[esp++] = namespace; + elementStack[esp++] = prefix; + elementStack[esp] = name; + + writer.write('<'); + if (!"".equals(prefix)) { + writer.write(prefix); + writer.write(':'); + } + + writer.write(name); + + pending = true; + + return this; + } + + public XmlSerializer attribute( + String namespace, + String name, + String value) + throws IOException { + if (!pending) + throw new IllegalStateException("illegal position for attribute"); + + // int cnt = nspCounts[depth]; + + if (namespace == null) + namespace = ""; + + // depth--; + // pending = false; + + String prefix = + "".equals(namespace) + ? "" + : getPrefix(namespace, false, true); + + // pending = true; + // depth++; + + /* if (cnt != nspCounts[depth]) { + writer.write(' '); + writer.write("xmlns"); + if (nspStack[cnt * 2] != null) { + writer.write(':'); + writer.write(nspStack[cnt * 2]); + } + writer.write("=\""); + writeEscaped(nspStack[cnt * 2 + 1], '"'); + writer.write('"'); + } + */ + + writer.write(' '); + if (!"".equals(prefix)) { + writer.write(prefix); + writer.write(':'); + } + writer.write(name); + writer.write('='); + char q = value.indexOf('"') == -1 ? '"' : '\''; + writer.write(q); + writeEscaped(value, q); + writer.write(q); + + return this; + } + + public void flush() throws IOException { + check(false); + writer.flush(); + } + /* + public void close() throws IOException { + check(); + writer.close(); + } + */ + public XmlSerializer endTag(String namespace, String name) + throws IOException { + + if (!pending) + depth--; + // if (namespace == null) + // namespace = ""; + + if ((namespace == null + && elementStack[depth * 3] != null) + || (namespace != null + && !namespace.equals(elementStack[depth * 3])) + || !elementStack[depth * 3 + 2].equals(name)) + throw new IllegalArgumentException("</{"+namespace+"}"+name+"> does not match start"); + + if (pending) { + check(true); + depth--; + } + else { + if (indent[depth + 1]) { + writer.write("\r\n"); + for (int i = 0; i < depth; i++) + writer.write(" "); + } + + writer.write("</"); + String prefix = elementStack[depth * 3 + 1]; + if (!"".equals(prefix)) { + writer.write(prefix); + writer.write(':'); + } + writer.write(name); + writer.write('>'); + } + + nspCounts[depth + 1] = nspCounts[depth]; + return this; + } + + public String getNamespace() { + return getDepth() == 0 ? null : elementStack[getDepth() * 3 - 3]; + } + + public String getName() { + return getDepth() == 0 ? null : elementStack[getDepth() * 3 - 1]; + } + + public int getDepth() { + return pending ? depth + 1 : depth; + } + + public XmlSerializer text(String text) throws IOException { + check(false); + indent[depth] = false; + writeEscaped(text, -1); + return this; + } + + public XmlSerializer text(char[] text, int start, int len) + throws IOException { + text(new String(text, start, len)); + return this; + } + + public void cdsect(String data) throws IOException { + check(false); + writer.write("<![CDATA["); + writer.write(data); + writer.write("]]>"); + } + + public void comment(String comment) throws IOException { + check(false); + writer.write("<!--"); + writer.write(comment); + writer.write("-->"); + } + + public void processingInstruction(String pi) + throws IOException { + check(false); + writer.write("<?"); + writer.write(pi); + writer.write("?>"); + } +} diff --git a/xml/src/main/java/org/kxml2/kdom/Document.java b/xml/src/main/java/org/kxml2/kdom/Document.java new file mode 100644 index 0000000..859334c --- /dev/null +++ b/xml/src/main/java/org/kxml2/kdom/Document.java @@ -0,0 +1,129 @@ +/* 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 org.kxml2.kdom; + +import java.io.*; + +import org.xmlpull.v1.*; +/** The document consists of some legacy events and a single root + element. This class basically adds some consistency checks to + Node. */ + +public class Document extends Node { + + protected int rootIndex = -1; + String encoding; + Boolean standalone; + + /** returns "#document" */ + + public String getEncoding () { + return encoding; + } + + public void setEncoding(String enc) { + this.encoding = enc; + } + + public void setStandalone (Boolean standalone) { + this.standalone = standalone; + } + + public Boolean getStandalone() { + return standalone; + } + + + public String getName() { + return "#document"; + } + + /** Adds a child at the given index position. Throws + an exception when a second root element is added */ + + public void addChild(int index, int type, Object child) { + if (type == ELEMENT) { + // if (rootIndex != -1) + // throw new RuntimeException("Only one document root element allowed"); + + rootIndex = index; + } + else if (rootIndex >= index) + rootIndex++; + + super.addChild(index, type, child); + } + + /** reads the document and checks if the last event + is END_DOCUMENT. If not, an exception is thrown. + The end event is consumed. For parsing partial + XML structures, consider using Node.parse (). */ + + public void parse(XmlPullParser parser) + throws IOException, XmlPullParserException { + + parser.require(XmlPullParser.START_DOCUMENT, null, null); + parser.nextToken (); + + encoding = parser.getInputEncoding(); + standalone = (Boolean)parser.getProperty ("http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone"); + + super.parse(parser); + + if (parser.getEventType() != XmlPullParser.END_DOCUMENT) + throw new RuntimeException("Document end expected!"); + + } + + public void removeChild(int index) { + if (index == rootIndex) + rootIndex = -1; + else if (index < rootIndex) + rootIndex--; + + super.removeChild(index); + } + + /** returns the root element of this document. */ + + public Element getRootElement() { + if (rootIndex == -1) + throw new RuntimeException("Document has no root element!"); + + return (Element) getChild(rootIndex); + } + + + /** Writes this node to the given XmlWriter. For node and document, + this method is identical to writeChildren, except that the + stream is flushed automatically. */ + + public void write(XmlSerializer writer) + throws IOException { + + writer.startDocument(encoding, standalone); + writeChildren(writer); + writer.endDocument(); + } + + +}
\ No newline at end of file diff --git a/xml/src/main/java/org/kxml2/kdom/Element.java b/xml/src/main/java/org/kxml2/kdom/Element.java new file mode 100644 index 0000000..61d5111 --- /dev/null +++ b/xml/src/main/java/org/kxml2/kdom/Element.java @@ -0,0 +1,336 @@ +/* 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 org.kxml2.kdom; + +import java.io.*; +import java.util.*; + +import org.xmlpull.v1.*; + +/** + * In order to create an element, please use the createElement method + * instead of invoking the constructor directly. The right place to + * add user defined initialization code is the init method. */ + +public class Element extends Node { + + protected String namespace; + protected String name; + protected ArrayList attributes; + protected Node parent; + protected ArrayList prefixes; + + public Element() { + } + + /** + * called when all properties are set, but before children + * are parsed. Please do not use setParent for initialization + * code any longer. */ + + public void init() { + } + + + + + /** + * removes all children and attributes */ + + public void clear() { + attributes = null; + children = null; + } + + /** + * Forwards creation request to parent if any, otherwise + * calls super.createElement. */ + + public Element createElement( + String namespace, + String name) { + + return (this.parent == null) + ? super.createElement(namespace, name) + : this.parent.createElement(namespace, name); + } + + /** + * Returns the number of attributes of this element. */ + + public int getAttributeCount() { + return attributes == null ? 0 : attributes.size(); + } + + public String getAttributeNamespace (int index) { + return ((String []) attributes.get(index)) [0]; + } + + public String getAttributeName (int index) { + return ((String []) attributes.get(index)) [1]; + } + + + public String getAttributeValue (int index) { + return ((String []) attributes.get(index)) [2]; + } + + + public String + getAttributeValue(String name) + { + return getAttributeValue(null, name); + } + + public String getAttributeValue (String namespace, String name) { + for (int i = 0; i < getAttributeCount (); i++) { + if (name.equals (getAttributeName (i)) + && (namespace == null || namespace.equals (getAttributeNamespace(i)))) { + return getAttributeValue (i); + } + } + return null; + } + + /** + * Returns the root node, determined by ascending to the + * all parents un of the root element. */ + + public Node getRoot() { + + Element current = this; + + while (current.parent != null) { + if (!(current.parent instanceof Element)) return current.parent; + current = (Element) current.parent; + } + + return current; + } + + /** + * returns the (local) name of the element */ + + public String getName() { + return name; + } + + /** + * returns the namespace of the element */ + + public String getNamespace() { + return namespace; + } + + + /** + * returns the namespace for the given prefix */ + + public String getNamespaceUri (String prefix) { + int cnt = getNamespaceCount (); + for (int i = 0; i < cnt; i++) { + if (prefix == getNamespacePrefix (i) || + (prefix != null && prefix.equals (getNamespacePrefix (i)))) + return getNamespaceUri (i); + } + return parent instanceof Element ? ((Element) parent).getNamespaceUri (prefix) : null; + } + + + /** + * returns the number of declared namespaces, NOT including + * parent elements */ + + public int getNamespaceCount () { + return (prefixes == null ? 0 : prefixes.size ()); + } + + + public String getNamespacePrefix (int i) { + return ((String []) prefixes.get(i)) [0]; + } + + public String getNamespaceUri (int i) { + return ((String []) prefixes.get(i)) [1]; + } + + + /** + * Returns the parent node of this element */ + + public Node getParent() { + return parent; + } + + /* + * Returns the parent element if available, null otherwise + + public Element getParentElement() { + return (parent instanceof Element) + ? ((Element) parent) + : null; + } +*/ + + /** + * Builds the child elements from the given Parser. By overwriting + * parse, an element can take complete control over parsing its + * subtree. */ + + public void parse(XmlPullParser parser) + throws IOException, XmlPullParserException { + + for (int i = parser.getNamespaceCount (parser.getDepth () - 1); + i < parser.getNamespaceCount (parser.getDepth ()); i++) { + setPrefix (parser.getNamespacePrefix (i), parser.getNamespaceUri(i)); + } + + + for (int i = 0; i < parser.getAttributeCount (); i++) + setAttribute (parser.getAttributeNamespace (i), +// parser.getAttributePrefix (i), + parser.getAttributeName (i), + parser.getAttributeValue (i)); + + + // if (prefixMap == null) throw new RuntimeException ("!!"); + + init(); + + + if (parser.isEmptyElementTag()) + parser.nextToken (); + else { + parser.nextToken (); + super.parse(parser); + + if (getChildCount() == 0) + addChild(IGNORABLE_WHITESPACE, ""); + } + + parser.require( + XmlPullParser.END_TAG, + getNamespace(), + getName()); + + parser.nextToken (); + } + + + /** + * Sets the given attribute; a value of null removes the attribute */ + + public void setAttribute (String namespace, String name, String value) { + if (attributes == null) + attributes = new ArrayList(); + + if (namespace == null) + namespace = ""; + + for (int i = attributes.size()-1; i >=0; i--){ + String[] attribut = (String[]) attributes.get(i); + if (attribut[0].equals(namespace) && + attribut[1].equals(name)){ + + if (value == null) { + attributes.remove(i); + } + else { + attribut[2] = value; + } + return; + } + } + + attributes.add(new String[] {namespace, name, value}); + } + + + /** + * Sets the given prefix; a namespace value of null removess the + * prefix */ + + public void setPrefix (String prefix, String namespace) { + if (prefixes == null) prefixes = new ArrayList(); + prefixes.add(new String [] {prefix, namespace}); + } + + + /** + * sets the name of the element */ + + public void setName(String name) { + this.name = name; + } + + /** + * sets the namespace of the element. Please note: For no + * namespace, please use Xml.NO_NAMESPACE, null is not a legal + * value. Currently, null is converted to Xml.NO_NAMESPACE, but + * future versions may throw an exception. */ + + public void setNamespace(String namespace) { + if (namespace == null) + throw new NullPointerException ("Use \"\" for empty namespace"); + this.namespace = namespace; + } + + /** + * Sets the Parent of this element. Automatically called from the + * add method. Please use with care, you can simply + * create inconsitencies in the document tree structure using + * this method! */ + + protected void setParent(Node parent) { + this.parent = parent; + } + + + /** + * Writes this element and all children to the given XmlWriter. */ + + public void write(XmlSerializer writer) + throws IOException { + + if (prefixes != null) { + for (int i = 0; i < prefixes.size(); i++) { + writer.setPrefix (getNamespacePrefix (i), getNamespaceUri (i)); + } + } + + writer.startTag( + getNamespace(), + getName()); + + int len = getAttributeCount(); + + for (int i = 0; i < len; i++) { + writer.attribute( + getAttributeNamespace(i), + getAttributeName(i), + getAttributeValue(i)); + } + + writeChildren(writer); + + writer.endTag(getNamespace (), getName ()); + } +} diff --git a/xml/src/main/java/org/kxml2/kdom/Node.java b/xml/src/main/java/org/kxml2/kdom/Node.java new file mode 100644 index 0000000..4855893 --- /dev/null +++ b/xml/src/main/java/org/kxml2/kdom/Node.java @@ -0,0 +1,366 @@ +/* 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 org.kxml2.kdom; + +import java.util.*; +import java.io.*; +import org.xmlpull.v1.*; +/** A common base class for Document and Element, also used for + storing XML fragments. */ + +public class Node { //implements XmlIO{ + + public static final int DOCUMENT = 0; + public static final int ELEMENT = 2; + public static final int TEXT = 4; + public static final int CDSECT = 5; + public static final int ENTITY_REF = 6; + public static final int IGNORABLE_WHITESPACE = 7; + public static final int PROCESSING_INSTRUCTION = 8; + public static final int COMMENT = 9; + public static final int DOCDECL = 10; + + protected ArrayList children; + protected StringBuffer types; + + /** inserts the given child object of the given type at the + given index. */ + + public void addChild(int index, int type, Object child) { + + if (child == null) + throw new NullPointerException(); + + if (children == null) { + children = new ArrayList(); + types = new StringBuffer(); + } + + if (type == ELEMENT) { + if (!(child instanceof Element)) + throw new RuntimeException("Element obj expected)"); + + ((Element) child).setParent(this); + } + else if (!(child instanceof String)) + throw new RuntimeException("String expected"); + + children.add(index, child); + types.insert(index, (char) type); + } + + /** convenience method for addChild (getChildCount (), child) */ + + public void addChild(int type, Object child) { + addChild(getChildCount(), type, child); + } + + /** Builds a default element with the given properties. Elements + should always be created using this method instead of the + constructor in order to enable construction of specialized + subclasses by deriving custom Document classes. Please note: + For no namespace, please use Xml.NO_NAMESPACE, null is not a + legal value. Currently, null is converted to Xml.NO_NAMESPACE, + but future versions may throw an exception. */ + + public Element createElement(String namespace, String name) { + + Element e = new Element(); + e.namespace = namespace == null ? "" : namespace; + e.name = name; + return e; + } + + /** Returns the child object at the given index. For child + elements, an Element object is returned. For all other child + types, a String is returned. */ + + public Object getChild(int index) { + return children.get(index); + } + + /** Returns the number of child objects */ + + public int getChildCount() { + return children == null ? 0 : children.size(); + } + + /** returns the element at the given index. If the node at the + given index is a text node, null is returned */ + + public Element getElement(int index) { + Object child = getChild(index); + return (child instanceof Element) ? (Element) child : null; + } + + /** Returns the element with the given namespace and name. If the + element is not found, or more than one matching elements are + found, an exception is thrown. */ + + public Element getElement(String namespace, String name) { + + int i = indexOf(namespace, name, 0); + int j = indexOf(namespace, name, i + 1); + + if (i == -1 || j != -1) + throw new RuntimeException( + "Element {" + + namespace + + "}" + + name + + (i == -1 ? " not found in " : " more than once in ") + + this); + + return getElement(i); + } + + /* returns "#document-fragment". For elements, the element name is returned + + public String getName() { + return "#document-fragment"; + } + + /** Returns the namespace of the current element. For Node + and Document, Xml.NO_NAMESPACE is returned. + + public String getNamespace() { + return ""; + } + + public int getNamespaceCount () { + return 0; + } + + /** returns the text content if the element has text-only + content. Throws an exception for mixed content + + public String getText() { + + StringBuffer buf = new StringBuffer(); + int len = getChildCount(); + + for (int i = 0; i < len; i++) { + if (isText(i)) + buf.append(getText(i)); + else if (getType(i) == ELEMENT) + throw new RuntimeException("not text-only content!"); + } + + return buf.toString(); + } + */ + + /** Returns the text node with the given index or null if the node + with the given index is not a text node. */ + + public String getText(int index) { + return (isText(index)) ? (String) getChild(index) : null; + } + + /** Returns the type of the child at the given index. Possible + types are ELEMENT, TEXT, COMMENT, and PROCESSING_INSTRUCTION */ + + public int getType(int index) { + return types.charAt(index); + } + + /** Convenience method for indexOf (getNamespace (), name, + startIndex). + + public int indexOf(String name, int startIndex) { + return indexOf(getNamespace(), name, startIndex); + } + */ + + /** Performs search for an element with the given namespace and + name, starting at the given start index. A null namespace + matches any namespace, please use Xml.NO_NAMESPACE for no + namespace). returns -1 if no matching element was found. */ + + public int indexOf(String namespace, String name, int startIndex) { + + int len = getChildCount(); + + for (int i = startIndex; i < len; i++) { + + Element child = getElement(i); + + if (child != null + && name.equals(child.getName()) + && (namespace == null || namespace.equals(child.getNamespace()))) + return i; + } + return -1; + } + + public boolean isText(int i) { + int t = getType(i); + return t == TEXT || t == IGNORABLE_WHITESPACE || t == CDSECT; + } + + /** Recursively builds the child elements from the given parser + until an end tag or end document is found. + The end tag is not consumed. */ + + public void parse(XmlPullParser parser) + throws IOException, XmlPullParserException { + + boolean leave = false; + + do { + int type = parser.getEventType(); + + // System.out.println(parser.getPositionDescription()); + + switch (type) { + + case XmlPullParser.START_TAG : + { + Element child = + createElement( + parser.getNamespace(), + parser.getName()); + // child.setAttributes (event.getAttributes ()); + addChild(ELEMENT, child); + + // order is important here since + // setparent may perform some init code! + + child.parse(parser); + break; + } + + case XmlPullParser.END_DOCUMENT : + case XmlPullParser.END_TAG : + leave = true; + break; + + default : + if (parser.getText() != null) + addChild( + type == XmlPullParser.ENTITY_REF ? TEXT : type, + parser.getText()); + else if ( + type == XmlPullParser.ENTITY_REF + && parser.getName() != null) { + addChild(ENTITY_REF, parser.getName()); + } + parser.nextToken(); + } + } + while (!leave); + } + + /** Removes the child object at the given index */ + + public void removeChild(int idx) { + children.remove(idx); + + /*** Modification by HHS - start ***/ + // types.deleteCharAt (index); + /***/ + int n = types.length() - 1; + + for (int i = idx; i < n; i++) + types.setCharAt(i, types.charAt(i + 1)); + + types.setLength(n); + + /*** Modification by HHS - end ***/ + } + + /* returns a valid XML representation of this Element including + attributes and children. + public String toString() { + try { + ByteArrayOutputStream bos = + new ByteArrayOutputStream(); + XmlWriter xw = + new XmlWriter(new OutputStreamWriter(bos)); + write(xw); + xw.close(); + return new String(bos.toByteArray()); + } + catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + */ + + /** Writes this node to the given XmlWriter. For node and document, + this method is identical to writeChildren, except that the + stream is flushed automatically. */ + + public void write(XmlSerializer writer) throws IOException { + writeChildren(writer); + writer.flush(); + } + + /** Writes the children of this node to the given XmlWriter. */ + + public void writeChildren(XmlSerializer writer) throws IOException { + if (children == null) + return; + + int len = children.size(); + + for (int i = 0; i < len; i++) { + int type = getType(i); + Object child = children.get(i); + switch (type) { + case ELEMENT : + ((Element) child).write(writer); + break; + + case TEXT : + writer.text((String) child); + break; + + case IGNORABLE_WHITESPACE : + writer.ignorableWhitespace((String) child); + break; + + case CDSECT : + writer.cdsect((String) child); + break; + + case COMMENT : + writer.comment((String) child); + break; + + case ENTITY_REF : + writer.entityRef((String) child); + break; + + case PROCESSING_INSTRUCTION : + writer.processingInstruction((String) child); + break; + + case DOCDECL : + writer.docdecl((String) child); + break; + + default : + throw new RuntimeException("Illegal type: " + type); + } + } + } +} diff --git a/xml/src/main/java/org/kxml2/wap/Wbxml.java b/xml/src/main/java/org/kxml2/wap/Wbxml.java new file mode 100644 index 0000000..5b0c2d3 --- /dev/null +++ b/xml/src/main/java/org/kxml2/wap/Wbxml.java @@ -0,0 +1,49 @@ +/* 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 org.kxml2.wap; + + +/** contains the WBXML constants */ + + +public interface Wbxml { + + static public final int SWITCH_PAGE = 0; + static public final int END = 1; + static public final int ENTITY = 2; + static public final int STR_I = 3; + static public final int LITERAL = 4; + static public final int EXT_I_0 = 0x40; + static public final int EXT_I_1 = 0x41; + static public final int EXT_I_2 = 0x42; + static public final int PI = 0x43; + static public final int LITERAL_C = 0x44; + static public final int EXT_T_0 = 0x80; + static public final int EXT_T_1 = 0x81; + static public final int EXT_T_2 = 0x82; + static public final int STR_T = 0x83; + static public final int LITERAL_A = 0x084; + static public final int EXT_0 = 0x0c0; + static public final int EXT_1 = 0x0c1; + static public final int EXT_2 = 0x0c2; + static public final int OPAQUE = 0x0c3; + static public final int LITERAL_AC = 0x0c4; +} diff --git a/xml/src/main/java/org/kxml2/wap/WbxmlParser.java b/xml/src/main/java/org/kxml2/wap/WbxmlParser.java new file mode 100644 index 0000000..c3852eb --- /dev/null +++ b/xml/src/main/java/org/kxml2/wap/WbxmlParser.java @@ -0,0 +1,1050 @@ +/* Copyright (c) 2002,2003,2004 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: Bjorn Aadland, Chris Bartley, Nicola Fankhauser, +// Victor Havin, Christian Kurzke, Bogdan Onoiu, +// Jain Sanjay, David Santoro. + +package org.kxml2.wap; + +import java.io.*; +import java.util.Vector; +import java.util.Hashtable; + +import org.xmlpull.v1.*; + + +public class WbxmlParser implements XmlPullParser { + + public static final int WAP_EXTENSION = 64; + + static final private String UNEXPECTED_EOF = + "Unexpected EOF"; + static final private String ILLEGAL_TYPE = + "Wrong event type"; + + private InputStream in; + + private int TAG_TABLE = 0; + private int ATTR_START_TABLE = 1; + private int ATTR_VALUE_TABLE = 2; + + private String[] attrStartTable; + private String[] attrValueTable; + private String[] tagTable; + private byte[] stringTable; + private Hashtable cacheStringTable = null; + private boolean processNsp; + + private int depth; + private String[] elementStack = new String[16]; + private String[] nspStack = new String[8]; + private int[] nspCounts = new int[4]; + + private int attributeCount; + private String[] attributes = new String[16]; + private int nextId = -2; + + private Vector tables = new Vector(); + + int version; + int publicIdentifierId; + int charSet; + + // StartTag current; + // ParseEvent next; + + private String prefix; + private String namespace; + private String name; + private String text; + // private String encoding; + private Object wapExtensionData; + private int wapExtensionCode; + + private int type; + private int codePage; + + private boolean degenerated; + private boolean isWhitespace; + private String encoding = null; + + public boolean getFeature(String feature) { + if (XmlPullParser + .FEATURE_PROCESS_NAMESPACES + .equals(feature)) + return processNsp; + else + return false; + } + + public String getInputEncoding() { + // should return someting depending on charSet here!!!!! + return encoding; + } + + public void defineEntityReplacementText( + String entity, + String value) + throws XmlPullParserException { + + // just ignore, has no effect + } + + public Object getProperty(String property) { + 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); + } + + return buf.toString(); + } + + public int getLineNumber() { + return -1; + } + + public int getColumnNumber() { + return -1; + } + + public boolean isWhitespace() + throws XmlPullParserException { + if (type != TEXT + && type != IGNORABLE_WHITESPACE + && type != CDSECT) + exception(ILLEGAL_TYPE); + return isWhitespace; + } + + public String getText() { + return text; + } + + public char[] getTextCharacters(int[] poslen) { + if (type >= TEXT) { + poslen[0] = 0; + poslen[1] = text.length(); + char[] buf = new char[text.length()]; + text.getChars(0, text.length(), buf, 0); + return buf; + } + + 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 { + + isWhitespace = true; + int minType = 9999; + + while (true) { + + String save = text; + + nextImpl(); + + if (type < minType) + minType = type; + + if (minType > CDSECT) continue; // no "real" event so far + + if (minType >= TEXT) { // text, see if accumulate + + if (save != null) text = text == null ? save : save + text; + + switch(peekId()) { + case Wbxml.ENTITY: + case Wbxml.STR_I: + case Wbxml.LITERAL: + case Wbxml.LITERAL_C: + case Wbxml.LITERAL_A: + case Wbxml.LITERAL_AC: continue; + } + } + + break; + } + + type = minType; + + if (type > TEXT) + type = TEXT; + + return type; + } + + + public int nextToken() throws XmlPullParserException, IOException { + + isWhitespace = true; + nextImpl(); + return type; + } + + + + 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 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 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 void setInput(Reader reader) throws XmlPullParserException { + exception("InputStream required"); + } + + public void setInput(InputStream in, String enc) + throws XmlPullParserException { + + this.in = in; + + try { + version = readByte(); + publicIdentifierId = readInt(); + + if (publicIdentifierId == 0) + readInt(); + + int charset = readInt(); // skip charset + + if (null == enc){ + switch (charset){ + case 4: encoding = "ISO-8859-1"; break; + case 106: encoding = "UTF-8"; break; + // add more if you need them + // http://www.iana.org/assignments/character-sets + // case MIBenum: encoding = Name break; + default: throw new UnsupportedEncodingException(""+charset); + } + }else{ + encoding = enc; + } + + int strTabSize = readInt(); + stringTable = new byte[strTabSize]; + + int ok = 0; + while(ok < strTabSize){ + int cnt = in.read(stringTable, ok, strTabSize - ok); + if(cnt <= 0) break; + ok += cnt; + } + + selectPage(0, true); + selectPage(0, false); + } + catch (IOException e) { + exception("Illegal input format"); + } + } + + public void setFeature(String feature, boolean value) + throws XmlPullParserException { + if (XmlPullParser.FEATURE_PROCESS_NAMESPACES.equals(feature)) + processNsp = value; + else + exception("unsupported feature: " + feature); + } + + public void setProperty(String property, Object value) + throws XmlPullParserException { + throw new XmlPullParserException("unsupported property: " + property); + } + + // ---------------------- private / internal methods + + 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("")) + exception("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) + 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) + throw new RuntimeException( + "Undefined Prefix: " + + attrPrefix + + " in " + + this); + + attributes[i] = attrNs; + attributes[i + 1] = attrPrefix; + attributes[i + 2] = attrName; + + 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) + exception("illegal tag name: " + name); + else if (cut != -1) { + prefix = name.substring(0, cut); + name = name.substring(cut + 1); + } + + this.namespace = getNamespace(prefix); + + if (this.namespace == null) { + if (prefix != null) + exception("undefined prefix: " + prefix); + this.namespace = NO_NAMESPACE; + } + + return any; + } + + private final void setTable(int page, int type, String[] table) { + if(stringTable != null){ + throw new RuntimeException("setXxxTable must be called before setInput!"); + } + while(tables.size() < 3*page +3){ + tables.addElement(null); + } + tables.setElementAt(table, page*3+type); + } + + + + + + private final void exception(String desc) + throws XmlPullParserException { + throw new XmlPullParserException(desc, this, null); + } + + + private void selectPage(int nr, boolean tags) throws XmlPullParserException{ + if(tables.size() == 0 && nr == 0) return; + + if(nr*3 > tables.size()) + exception("Code Page "+nr+" undefined!"); + + if(tags) + tagTable = (String[]) tables.elementAt(nr * 3 + TAG_TABLE); + else { + attrStartTable = (String[]) tables.elementAt(nr * 3 + ATTR_START_TABLE); + attrValueTable = (String[]) tables.elementAt(nr * 3 + ATTR_VALUE_TABLE); + } + } + + private final void nextImpl() + throws IOException, XmlPullParserException { + + String s; + + if (type == END_TAG) { + depth--; + } + + if (degenerated) { + type = XmlPullParser.END_TAG; + degenerated = false; + return; + } + + text = null; + prefix = null; + name = null; + + int id = peekId (); + while(id == Wbxml.SWITCH_PAGE){ + nextId = -2; + selectPage(readByte(), true); + id = peekId(); + } + nextId = -2; + + switch (id) { + case -1 : + type = XmlPullParser.END_DOCUMENT; + break; + + case Wbxml.END : + { + int sp = (depth - 1) << 2; + + type = END_TAG; + namespace = elementStack[sp]; + prefix = elementStack[sp + 1]; + name = elementStack[sp + 2]; + } + break; + + case Wbxml.ENTITY : + { + type = ENTITY_REF; + char c = (char) readInt(); + text = "" + c; + name = "#" + ((int) c); + } + + break; + + case Wbxml.STR_I : + type = TEXT; + text = readStrI(); + break; + + case Wbxml.EXT_I_0 : + case Wbxml.EXT_I_1 : + case Wbxml.EXT_I_2 : + case Wbxml.EXT_T_0 : + case Wbxml.EXT_T_1 : + case Wbxml.EXT_T_2 : + case Wbxml.EXT_0 : + case Wbxml.EXT_1 : + case Wbxml.EXT_2 : + case Wbxml.OPAQUE : + parseWapExtension(id); + break; + + case Wbxml.PI : + throw new RuntimeException("PI curr. not supp."); + // readPI; + // break; + + case Wbxml.STR_T : + { + type = TEXT; + text = readStrT(); + } + break; + + default : + parseElement(id); + } + // } + // while (next == null); + + // return next; + } + + + + public void parseWapExtension(int id) + throws IOException, XmlPullParserException { + + type = WAP_EXTENSION; + wapExtensionCode = id; + + switch (id) { + case Wbxml.EXT_I_0 : + case Wbxml.EXT_I_1 : + case Wbxml.EXT_I_2 : + wapExtensionData = readStrI(); + break; + + case Wbxml.EXT_T_0 : + case Wbxml.EXT_T_1 : + case Wbxml.EXT_T_2 : + wapExtensionData = new Integer(readInt()); + break; + + case Wbxml.EXT_0 : + case Wbxml.EXT_1 : + case Wbxml.EXT_2 : + break; + + case Wbxml.OPAQUE : + { + int len = readInt(); + byte[] buf = new byte[len]; + + for (int i = 0; + i < len; + i++) // enhance with blockread! + buf[i] = (byte) readByte(); + + wapExtensionData = buf; + } // case OPAQUE + break; + + default: + exception("illegal id: "+id); + } // SWITCH + } + + public void readAttr() throws IOException, XmlPullParserException { + + int id = readByte(); + int i = 0; + + while (id != 1) { + + while(id == Wbxml.SWITCH_PAGE){ + selectPage(readByte(), false); + id = readByte(); + } + + String name = resolveId(attrStartTable, id); + StringBuffer value; + + int cut = name.indexOf('='); + + if (cut == -1) + value = new StringBuffer(); + else { + value = + new StringBuffer(name.substring(cut + 1)); + name = name.substring(0, cut); + } + + id = readByte(); + while (id > 128 + || id == Wbxml.SWITCH_PAGE + || id == Wbxml.ENTITY + || id == Wbxml.STR_I + || id == Wbxml.STR_T + || (id >= Wbxml.EXT_I_0 && id <= Wbxml.EXT_I_2) + || (id >= Wbxml.EXT_T_0 && id <= Wbxml.EXT_T_2)) { + + switch (id) { + case Wbxml.SWITCH_PAGE : + selectPage(readByte(), false); + break; + + case Wbxml.ENTITY : + value.append((char) readInt()); + break; + + case Wbxml.STR_I : + value.append(readStrI()); + break; + + case Wbxml.EXT_I_0 : + case Wbxml.EXT_I_1 : + case Wbxml.EXT_I_2 : + case Wbxml.EXT_T_0 : + case Wbxml.EXT_T_1 : + case Wbxml.EXT_T_2 : + case Wbxml.EXT_0 : + case Wbxml.EXT_1 : + case Wbxml.EXT_2 : + case Wbxml.OPAQUE : + + throw new RuntimeException("wap extension in attr not supported yet"); + + /* + ParseEvent e = parseWapExtension(id); + if (!(e.getType() != Xml.TEXT + && e.getType() != Xml.WHITESPACE)) + throw new RuntimeException("parse WapExtension must return Text Event in order to work inside Attributes!"); + + value.append(e.getText()); + + //value.append (handleExtension (id)); // skip EXT in ATTR + //break; + */ + + case Wbxml.STR_T : + value.append(readStrT()); + break; + + default : + value.append( + resolveId(attrValueTable, id)); + } + + id = readByte(); + } + + attributes = ensureCapacity(attributes, i + 4); + + attributes[i++] = ""; + attributes[i++] = null; + attributes[i++] = name; + attributes[i++] = value.toString(); + + attributeCount++; + } + } + + private int peekId () throws IOException { + if (nextId == -2) { + nextId = in.read (); + } + return nextId; + } + + + + + String resolveId(String[] tab, int id) throws IOException { + int idx = (id & 0x07f) - 5; + if (idx == -1) + return readStrT(); + if (idx < 0 + || tab == null + || idx >= tab.length + || tab[idx] == null) + throw new IOException("id " + id + " undef."); + + return tab[idx]; + } + + void parseElement(int id) + throws IOException, XmlPullParserException { + + type = START_TAG; + name = resolveId(tagTable, id & 0x03f); + + attributeCount = 0; + if ((id & 128) != 0) { + readAttr(); + } + + degenerated = (id & 64) == 0; + + int sp = depth++ << 2; + + // transfer to element stack + + 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]; + + 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; + + } + + 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; + } + + int readByte() throws IOException { + int i = in.read(); + if (i == -1) + throw new IOException("Unexpected EOF"); + return i; + } + + int readInt() throws IOException { + int result = 0; + int i; + + do { + i = readByte(); + result = (result << 7) | (i & 0x7f); + } + while ((i & 0x80) != 0); + + return result; + } + + String readStrI() throws IOException { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + boolean wsp = true; + while (true){ + int i = in.read(); + if (i == 0){ + break; + } + if (i == -1){ + throw new IOException(UNEXPECTED_EOF); + } + if (i > 32){ + wsp = false; + } + buf.write(i); + } + isWhitespace = wsp; + String result = new String(buf.toByteArray(), encoding); + buf.close(); + return result; + } + + String readStrT() throws IOException { + int pos = readInt(); + // As the main reason of stringTable is compression we build a cache of Strings + // stringTable is supposed to help create Strings from parts which means some cache hit rate + // This will help to minimize the Strings created when invoking readStrT() repeatedly + if (cacheStringTable == null){ + //Lazy init if device is not using StringTable but inline 0x03 strings + cacheStringTable = new Hashtable(); + } + String forReturn = (String) cacheStringTable.get(new Integer(pos)); + if (forReturn == null){ + + int end = pos; + while(end < stringTable.length && stringTable[end] != '\0'){ + end++; + } + forReturn = new String(stringTable, pos, end-pos, encoding); + cacheStringTable.put(new Integer(pos), forReturn); + } + return forReturn; + } + + /** + * Sets the tag table for a given page. + * The first string in the array defines tag 5, the second tag 6 etc. + */ + + public void setTagTable(int page, String[] table) { + setTable(page, TAG_TABLE, table); + + // this.tagTable = tagTable; + // if (page != 0) + // throw new RuntimeException("code pages curr. not supp."); + } + + /** Sets the attribute start Table for a given page. + * The first string in the array defines attribute + * 5, the second attribute 6 etc. Please use the + * character '=' (without quote!) as delimiter + * between the attribute name and the (start of the) value + */ + + public void setAttrStartTable( + int page, + String[] table) { + + setTable(page, ATTR_START_TABLE, table); + } + + /** Sets the attribute value Table for a given page. + * The first string in the array defines attribute value 0x85, + * the second attribute value 0x86 etc. + */ + + public void setAttrValueTable( + int page, + String[] table) { + + setTable(page, ATTR_VALUE_TABLE, table); + } + +} diff --git a/xml/src/main/java/org/kxml2/wap/WbxmlSerializer.java b/xml/src/main/java/org/kxml2/wap/WbxmlSerializer.java new file mode 100644 index 0000000..e4447b0 --- /dev/null +++ b/xml/src/main/java/org/kxml2/wap/WbxmlSerializer.java @@ -0,0 +1,418 @@ +/* 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: Bogdan Onoiu (Genderal character encoding abstraction and UTF-8 Support) + +package org.kxml2.wap; + +import java.io.*; +import java.util.*; + +import org.xmlpull.v1.*; + +// TODO: make some of the "direct" WBXML token writing methods public?? + +/** + * A class for writing WBXML. + * + */ + + + +public class WbxmlSerializer implements XmlSerializer { + + Hashtable stringTable = new Hashtable(); + + OutputStream out; + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + ByteArrayOutputStream stringTableBuf = new ByteArrayOutputStream(); + + String pending; + int depth; + String name; + String namespace; + Vector attributes = new Vector(); + + Hashtable attrStartTable = new Hashtable(); + Hashtable attrValueTable = new Hashtable(); + Hashtable tagTable = new Hashtable(); + + private int attrPage; + private int tagPage; + + private String encoding = null; + + + public XmlSerializer attribute(String namespace, String name, String value) { + attributes.addElement(name); + attributes.addElement(value); + return this; + } + + + public void cdsect (String cdsect) throws IOException{ + text (cdsect); + } + + + + /* silently ignore comment */ + + public void comment (String comment) { + } + + + public void docdecl (String docdecl) { + throw new RuntimeException ("Cannot write docdecl for WBXML"); + } + + + public void entityRef (String er) { + throw new RuntimeException ("EntityReference not supported for WBXML"); + } + + public int getDepth() { + return depth; + } + + + public boolean getFeature (String name) { + return false; + } + + public String getNamespace() { + throw new RuntimeException("NYI"); + } + + public String getName() { + throw new RuntimeException("NYI"); + } + + public String getPrefix(String nsp, boolean create) { + throw new RuntimeException ("NYI"); + } + + + public Object getProperty (String name) { + return null; + } + + public void ignorableWhitespace (String sp) { + } + + + public void endDocument() throws IOException { + writeInt(out, stringTableBuf.size()); + + // write StringTable + + out.write(stringTableBuf.toByteArray()); + + // write buf + + out.write(buf.toByteArray()); + + // ready! + + out.flush(); + } + + + /** ATTENTION: flush cannot work since Wbxml documents require + need buffering. Thus, this call does nothing. */ + + public void flush() { + } + + + public void checkPending(boolean degenerated) throws IOException { + if (pending == null) + return; + + int len = attributes.size(); + + int[] idx = (int[]) tagTable.get(pending); + + // if no entry in known table, then add as literal + if (idx == null) { + buf.write( + len == 0 + ? (degenerated ? Wbxml.LITERAL : Wbxml.LITERAL_C) + : (degenerated ? Wbxml.LITERAL_A : Wbxml.LITERAL_AC)); + + writeStrT(pending); + } + else { + if(idx[0] != tagPage){ + tagPage=idx[0]; + buf.write(0); + buf.write(tagPage); + } + + buf.write( + len == 0 + ? (degenerated ? idx[1] : idx[1] | 64) + : (degenerated + ? idx[1] | 128 + : idx[1] | 192)); + + } + + for (int i = 0; i < len;) { + idx = (int[]) attrStartTable.get(attributes.elementAt(i)); + + if (idx == null) { + buf.write(Wbxml.LITERAL); + writeStrT((String) attributes.elementAt(i)); + } + else { + if(idx[0] != attrPage){ + attrPage = idx[1]; + buf.write(0); + buf.write(attrPage); + } + buf.write(idx[1]); + } + idx = (int[]) attrValueTable.get(attributes.elementAt(++i)); + if (idx == null) { + buf.write(Wbxml.STR_I); + writeStrI(buf, (String) attributes.elementAt(i)); + } + else { + if(idx[0] != attrPage){ + attrPage = idx[1]; + buf.write(0); + buf.write(attrPage); + } + buf.write(idx[1]); + } + ++i; + } + + if (len > 0) + buf.write(Wbxml.END); + + pending = null; + attributes.removeAllElements(); + } + + + public void processingInstruction(String pi) { + throw new RuntimeException ("PI NYI"); + } + + + public void setFeature(String name, boolean value) { + throw new IllegalArgumentException ("unknown feature "+name); + } + + + + public void setOutput (Writer writer) { + throw new RuntimeException ("Wbxml requires an OutputStream!"); + } + + public void setOutput (OutputStream out, String encoding) throws IOException { + + if (encoding != null) throw new IllegalArgumentException ("encoding not yet supported for WBXML"); + + this.out = out; + + buf = new ByteArrayOutputStream(); + stringTableBuf = new ByteArrayOutputStream(); + + // ok, write header + } + + + public void setPrefix(String prefix, String nsp) { + throw new RuntimeException("NYI"); + } + + public void setProperty(String property, Object value) { + throw new IllegalArgumentException ("unknown property "+property); + } + + + public void startDocument(String s, Boolean b) throws IOException{ + out.write(0x03); // version 1.3 + // http://www.openmobilealliance.org/tech/omna/omna-wbxml-public-docid.htm + out.write(0x01); // unknown or missing public identifier + + // default encoding is UTF-8 + String[] encodings = { "UTF-8", "ISO-8859-1" }; + if (s == null || s.toUpperCase().equals(encodings[0])){ + encoding = encodings[0]; + out.write(106); + }else if (true == s.toUpperCase().equals(encodings[1])){ + encoding = encodings[1]; + out.write(0x04); + }else{ + throw new UnsupportedEncodingException(s); + } + } + + + public XmlSerializer startTag(String namespace, String name) throws IOException { + + if (namespace != null && !"".equals(namespace)) + throw new RuntimeException ("NSP NYI"); + + //current = new State(current, prefixMap, name); + + checkPending(false); + pending = name; + depth++; + + return this; + } + + public XmlSerializer text(char[] chars, int start, int len) throws IOException { + + checkPending(false); + + buf.write(Wbxml.STR_I); + writeStrI(buf, new String(chars, start, len)); + + return this; + } + + public XmlSerializer text(String text) throws IOException { + + checkPending(false); + + buf.write(Wbxml.STR_I); + writeStrI(buf, text); + + return this; + } + + + + public XmlSerializer endTag(String namespace, String name) throws IOException { + + // current = current.prev; + + if (pending != null) + checkPending(true); + else + buf.write(Wbxml.END); + + depth--; + + return this; + } + + /** currently ignored! */ + + public void writeLegacy(int type, String data) { + } + + // ------------- internal methods -------------------------- + + static void writeInt(OutputStream out, int i) throws IOException { + byte[] buf = new byte[5]; + int idx = 0; + + do { + buf[idx++] = (byte) (i & 0x7f); + i = i >> 7; + } + while (i != 0); + + while (idx > 1) { + out.write(buf[--idx] | 0x80); + } + out.write(buf[0]); + } + + static void writeStrI(OutputStream out, String s) throws IOException { + for (int i = 0; i < s.length(); i++) { + out.write((byte) s.charAt(i)); + } + out.write(0); + } + + void writeStrT(String s) throws IOException { + + Integer idx = (Integer) stringTable.get(s); + + if (idx == null) { + idx = new Integer(stringTableBuf.size()); + stringTable.put(s, idx); + writeStrI(stringTableBuf, s); + stringTableBuf.flush(); + } + + writeInt(buf, idx.intValue()); + } + + /** + * Sets the tag table for a given page. + * The first string in the array defines tag 5, the second tag 6 etc. + */ + + public void setTagTable(int page, String[] tagTable) { + // clear entries in tagTable! + if (page != 0) + return; + + for (int i = 0; i < tagTable.length; i++) { + if (tagTable[i] != null) { + Object idx = new int[]{page, i+5}; + this.tagTable.put(tagTable[i], idx); + } + } + } + + /** + * Sets the attribute start Table for a given page. + * The first string in the array defines attribute + * 5, the second attribute 6 etc. + * Please use the + * character '=' (without quote!) as delimiter + * between the attribute name and the (start of the) value + */ + public void setAttrStartTable(int page, String[] attrStartTable) { + + for (int i = 0; i < attrStartTable.length; i++) { + if (attrStartTable[i] != null) { + Object idx = new int[] {page, i + 5}; + this.attrStartTable.put(attrStartTable[i], idx); + } + } + } + + /** + * Sets the attribute value Table for a given page. + * The first string in the array defines attribute value 0x85, + * the second attribute value 0x86 etc. + */ + public void setAttrValueTable(int page, String[] attrValueTable) { + // clear entries in this.table! + for (int i = 0; i < attrValueTable.length; i++) { + if (attrValueTable[i] != null) { + Object idx = new int[]{page, i + 0x085}; + this.attrValueTable.put(attrValueTable[i], idx); + } + } + } +} diff --git a/xml/src/main/java/org/kxml2/wap/syncml/SyncML.java b/xml/src/main/java/org/kxml2/wap/syncml/SyncML.java new file mode 100644 index 0000000..5ea8496 --- /dev/null +++ b/xml/src/main/java/org/kxml2/wap/syncml/SyncML.java @@ -0,0 +1,192 @@ +package org.kxml2.wap.syncml; + +import org.kxml2.wap.*; + +public abstract class SyncML { + + + // SyncML-Common (-//SYNCML//DTD SyncML 1.2//EN and -//SYNCML//DTD MetInf 1.2//EN) support + + public static WbxmlParser createParser() { + WbxmlParser p = new WbxmlParser(); + p.setTagTable(0, TAG_TABLE_0); + p.setTagTable(1, TAG_TABLE_1); + return p; + } + + public static WbxmlSerializer createSerializer() { + WbxmlSerializer s = new WbxmlSerializer(); + s.setTagTable(0, TAG_TABLE_0); + s.setTagTable(1, TAG_TABLE_1); + return s; + } + + + // SyncML-Common + DMDDF (-//OMA//DTD-DM-DDF 1.2//EN) support + + public static WbxmlParser createDMParser() { + WbxmlParser p = createParser(); + p.setTagTable(2, TAG_TABLE_2_DM); + return p; + } + + public static WbxmlSerializer createDMSerializer() { + WbxmlSerializer s = createSerializer(); + s.setTagTable(2, TAG_TABLE_2_DM); + return s; + } + + // Tables + + public static final String [] TAG_TABLE_0 = { + + // -//SYNCML//DTD SyncML 1.2//EN + + "Add", // 0x05 + "Alert", // 0x06 + "Archive", // 0x07 + "Atomic", // 0x08 + "Chal", // 0x09 + "Cmd", // 0x0a + "CmdID", // 0x0b + "CmdRef", // 0x0c + "Copy", // 0x0d + "Cred", // 0x0e + "Data", // 0x0f + "Delete", // 0x10 + "Exec", // 0x11 + "Final", // 0x12 + "Get", // 0x13 + "Item", // 0x14 + "Lang", // 0x15 + "LocName", // 0x16 + "LocURI", // 0x17 + "Map", // 0x18 + "MapItem", // 0x19 + "Meta", // 0x1a + "MsgID", // 0x1b + "MsgRef", // 0x1c + "NoResp", // 0x1d + "NoResults", // 0x1e + "Put", // 0x1f + "Replace", // 0x20 + "RespURI", // 0x21 + "Results", // 0x22 + "Search", // 0x23 + "Sequence", // 0x24 + "SessionID", // 0x25 + "SftDel", // 0x26 + "Source", // 0x27 + "SourceRef", // 0x28 + "Status", // 0x29 + "Sync", // 0x2a + "SyncBody", // 0x2b + "SyncHdr", // 0x2c + "SyncML", // 0x2d + "Target", // 0x2e + "TargetRef", // 0x2f + "Reserved for future use", // 0x30 + "VerDTD", // 0x31 + "VerProto", // 0x32 + "NumberOfChanged",// 0x33 + "MoreData", // 0x34 + "Field", // 0x35 + "Filter", // 0x36 + "Record", // 0x37 + "FilterType", // 0x38 + "SourceParent", // 0x39 + "TargetParent", // 0x3a + "Move", // 0x3b + "Correlator" // 0x3c + }; + + public static final String [] TAG_TABLE_1 = { + + // -//SYNCML//DTD MetInf 1.2//EN + + "Anchor", // 0x05 + "EMI", // 0x06 + "Format", // 0x07 + "FreeID", // 0x08 + "FreeMem", // 0x09 + "Last", // 0x0a + "Mark", // 0x0b + "MaxMsgSize", // 0x0c + "Mem", // 0x0d + "MetInf", // 0x0e + "Next", // 0x0f + "NextNonce", // 0x10 + "SharedMem", // 0x11 + "Size", // 0x12 + "Type", // 0x13 + "Version", // 0x14 + "MaxObjSize", // 0x15 + "FieldLevel" // 0x16 + + }; + + public static final String [] TAG_TABLE_2_DM = { + + // -//OMA//DTD-DM-DDF 1.2//EN + + "AccessType", // 0x05 + "ACL", // 0x06 + "Add", // 0x07 + "b64", // 0x08 + "bin", // 0x09 + "bool", // 0x0a + "chr", // 0x0b + "CaseSense", // 0x0c + "CIS", // 0x0d + "Copy", // 0x0e + "CS", // 0x0f + "date", // 0x10 + "DDFName", // 0x11 + "DefaultValue", // 0x12 + "Delete", // 0x13 + "Description", // 0x14 + "DDFFormat", // 0x15 + "DFProperties", // 0x16 + "DFTitle", // 0x17 + "DFType", // 0x18 + "Dynamic", // 0x19 + "Exec", // 0x1a + "float", // 0x1b + "Format", // 0x1c + "Get", // 0x1d + "int", // 0x1e + "Man", // 0x1f + "MgmtTree", // 0x20 + "MIME", // 0x21 + "Mod", // 0x22 + "Name", // 0x23 + "Node", // 0x24 + "node", // 0x25 + "NodeName", // 0x26 + "null", // 0x27 + "Occurence", // 0x28 + "One", // 0x29 + "OneOrMore", // 0x2a + "OneOrN", // 0x2b + "Path", // 0x2c + "Permanent", // 0x2d + "Replace", // 0x2e + "RTProperties", // 0x2f + "Scope", // 0x30 + "Size", // 0x31 + "time", // 0x32 + "Title", // 0x33 + "TStamp", // 0x34 + "Type", // 0x35 + "Value", // 0x36 + "VerDTD", // 0x37 + "VerNo", // 0x38 + "xml", // 0x39 + "ZeroOrMore", // 0x3a + "ZeroOrN", // 0x3b + "ZeroOrOne" // 0x3c + + }; + +} + diff --git a/xml/src/main/java/org/kxml2/wap/wml/Wml.java b/xml/src/main/java/org/kxml2/wap/wml/Wml.java new file mode 100644 index 0000000..7e925d8 --- /dev/null +++ b/xml/src/main/java/org/kxml2/wap/wml/Wml.java @@ -0,0 +1,233 @@ +package org.kxml2.wap.wml; + +import org.kxml2.wap.*; + + +/** This class contains the wml coding tables for elements + * and attributes needed by the WmlParser. + */ + + +public abstract class Wml { + + /** Creates a WbxmlParser with the WML code pages set */ + + public static WbxmlParser createParser() { + WbxmlParser p = new WbxmlParser(); + p.setTagTable(0, TAG_TABLE); + p.setAttrStartTable(0, ATTR_START_TABLE); + p.setAttrValueTable(0, ATTR_VALUE_TABLE); + return p; + } + + public static WbxmlSerializer createSerializer() { + WbxmlSerializer s = new WbxmlSerializer(); + s.setTagTable(0, TAG_TABLE); + s.setAttrStartTable(0, ATTR_START_TABLE); + s.setAttrValueTable(0, ATTR_VALUE_TABLE); + return s; + } + + + public static final String [] TAG_TABLE = { + + null, // 05 + null, // 06 + null, // 07 + null, // 08 + null, // 09 + null, // 0A + null, // 0B + null, // 0C + null, // 0D + null, // 0E + null, // 0F + + null, // 10 + null, // 11 + null, // 12 + null, // 13 + null, // 14 + null, // 15 + null, // 16 + null, // 17 + null, // 18 + null, // 19 + null, // 1A + null, // 1B + "a", // 1C + "td", // 1D + "tr", // 1E + "table", // 1F + + "p", // 20 + "postfield", // 21 + "anchor", // 22 + "access", // 23 + "b", // 24 + "big", // 25 + "br", // 26 + "card", // 27 + "do", // 28 + "em", // 29 + "fieldset", // 2A + "go", // 2B + "head", // 2C + "i", // 2D + "img", // 2E + "input", // 2F + + "meta", // 30 + "noop", // 31 + "prev", // 32 + "onevent", // 33 + "optgroup", // 34 + "option", // 35 + "refresh", // 36 + "select", // 37 + "small", // 38 + "strong", // 39 + null, // 3A + "template", // 3B + "timer", // 3C + "u", // 3D + "setvar", // 3E + "wml", // 3F + }; + + + public static final String [] ATTR_START_TABLE = { + "accept-charset", // 05 + "align=bottom", // 06 + "align=center", // 07 + "align=left", // 08 + "align=middle", // 09 + "align=right", // 0A + "align=top", // 0B + "alt", // 0C + "content", // 0D + null, // 0E + "domain", // 0F + + "emptyok=false", // 10 + "emptyok=true", // 11 + "format", // 12 + "height", // 13 + "hspace", // 14 + "ivalue", // 15 + "iname", // 16 + null, // 17 + "label", // 18 + "localsrc", // 19 + "maxlength", // 1A + "method=get", // 1B + "method=post", // 1C + "mode=nowrap", // 1D + "mode=wrap", // 1E + "multiple=false", // 1F + + "multiple=true", // 20 + "name", // 21 + "newcontext=false", // 22 + "newcontext=true", // 23 + "onpick", // 24 + "onenterbackward", // 25 + "onenterforward", // 26 + "ontimer", // 27 + "optimal=false", // 28 + "optimal=true", // 29 + "path", // 2A + null, // 2B + null, // 2C + null, // 2D + "scheme", // 2E + "sendreferer=false", // 2F + + "sendreferer=true", // 30 + "size", // 31 + "src", // 32 + "ordered=true", // 33 + "ordered=false", // 34 + "tabindex", // 35 + "title", // 36 + "type", // 37 + "type=accept", // 38 + "type=delete", // 39 + "type=help", // 3A + "type=password", // 3B + "type=onpick", // 3C + "type=onenterbackward", // 3D + "type=onenterforward", // 3E + "type=ontimer", // 3F + + null, // 40 + null, // 41 + null, // 42 + null, // 43 + null, // 44 + "type=options", // 45 + "type=prev", // 46 + "type=reset", // 47 + "type=text", // 48 + "type=vnd.", // 49 + "href", // 4A + "href=http://", // 4B + "href=https://", // 4C + "value", // 4D + "vspace", // 4E + "width", // 4F + + "xml:lang", // 50 + null, // 51 + "align", // 52 + "columns", // 53 + "class", // 54 + "id", // 55 + "forua=false", // 56 + "forua=true", // 57 + "src=http://", // 58 + "src=https://", // 59 + "http-equiv", // 5A + "http-equiv=Content-Type", // 5B + "content=application/vnd.wap.wmlc;charset=", // 5C + "http-equiv=Expires", // 5D + null, // 5E + null, // 5F + }; + + + public static final String [] ATTR_VALUE_TABLE = { + ".com/", // 85 + ".edu/", // 86 + ".net/", // 87 + ".org/", // 88 + "accept", // 89 + "bottom", // 8A + "clear", // 8B + "delete", // 8C + "help", // 8D + "http://", // 8E + "http://www.", // 8F + + "https://", // 90 + "https://www.", // 91 + null, // 92 + "middle", // 93 + "nowrap", // 94 + "onpick", // 95 + "onenterbackward", // 96 + "onenterforward", // 97 + "ontimer", // 98 + "options", // 99 + "password", // 9A + "reset", // 9B + null, // 9C + "text", // 9D + "top", // 9E + "unknown", // 9F + + "wrap", // A0 + "www.", // A1 + }; +} + diff --git a/xml/src/main/java/org/kxml2/wap/wv/WV.java b/xml/src/main/java/org/kxml2/wap/wv/WV.java new file mode 100644 index 0000000..e2afbfb --- /dev/null +++ b/xml/src/main/java/org/kxml2/wap/wv/WV.java @@ -0,0 +1,593 @@ +package org.kxml2.wap.wv; + +import java.io.IOException; + +import org.kxml2.wap.*; + +/* + + * WV.java + + * + + * Created on 25 September 2003, 10:40 + + */ + + + + + + /** + * Wireless Village CSP 1.1 ("OMA-WV-CSP-V1_1-20021001-A.pdf") + * Wireless Village CSP 1.2 ("OMA-IMPS-WV-CSP_WBXML-v1_2-20030221-C.PDF") + * There are some bugs in the 1.2 spec but this is Ok. 1.2 is candidate + * + + * @author Bogdan Onoiu + + */ + +public abstract class WV { + + + + + + public static WbxmlParser createParser () throws IOException { + + WbxmlParser parser = new WbxmlParser(); + + parser.setTagTable (0, WV.tagTablePage0); + parser.setTagTable (1, WV.tagTablePage1); + parser.setTagTable (2, WV.tagTablePage2); + parser.setTagTable (3, WV.tagTablePage3); + parser.setTagTable (4, WV.tagTablePage4); + parser.setTagTable (5, WV.tagTablePage5); + parser.setTagTable (6, WV.tagTablePage6); + parser.setTagTable (7, WV.tagTablePage7); + parser.setTagTable (8, WV.tagTablePage8); + parser.setTagTable (9, WV.tagTablePage9); + parser.setTagTable (10, WV.tagTablePageA); + + parser.setAttrStartTable (0, WV.attrStartTable); + + parser.setAttrValueTable (0, WV.attrValueTable); + + return parser; + } + + + + public static final String [] tagTablePage0 = { + /* Common ... continue on Page 0x09 */ + "Acceptance", //0x00, 0x05 + "AddList", //0x00, 0x06 + "AddNickList", //0x00, 0x07 + "SName", //0x00, 0x08 + "WV-CSP-Message", //0x00, 0x09 + "ClientID", //0x00, 0x0A + "Code", //0x00, 0x0B + "ContactList", //0x00, 0x0C + "ContentData", //0x00, 0x0D + "ContentEncoding",//0x00, 0x0E + "ContentSize", //0x00, 0x0F + "ContentType", //0x00, 0x10 + "DateTime", //0x00, 0x11 + "Description", //0x00, 0x12 + "DetailedResult", //0x00, 0x13 + "EntityList", //0x00, 0x14 + "Group", //0x00, 0x15 + "GroupID", //0x00, 0x16 + "GroupList", //0x00, 0x17 + "InUse", //0x00, 0x18 + "Logo", //0x00, 0x19 + "MessageCount", //0x00, 0x1A + "MessageID", //0x00, 0x1B + "MessageURI", //0x00, 0x1C + "MSISDN", //0x00, 0x1D + "Name", //0x00, 0x1E + "NickList", //0x00, 0x1F + "NickName", //0x00, 0x20 + "Poll", //0x00, 0x21 + "Presence", //0x00, 0x22 + "PresenceSubList",//0x00, 0x23 + "PresenceValue", //0x00, 0x24 + "Property", //0x00, 0x25 + "Qualifier", //0x00, 0x26 + "Recipient", //0x00, 0x27 + "RemoveList", //0x00, 0x28 + "RemoveNickList", //0x00, 0x29 + "Result", //0x00, 0x2A + "ScreenName", //0x00, 0x2B + "Sender", //0x00, 0x2C + "Session", //0x00, 0x2D + "SessionDescriptor",//0x00, 0x2E + "SessionID", //0x00, 0x2F + "SessionType", //0x00, 0x30 + "Status", //0x00, 0x31 + "Transaction", //0x00, 0x32 + "TransactionContent",//0x00, 0x33 + "TransactionDescriptor",//0x00, 0x34 + "TransactionID", //0x00, 0x35 + "TransactionMode",//0x00, 0x36 + "URL", //0x00, 0x37 + "URLList", //0x00, 0x38 + "User", //0x00, 0x39 + "UserID", //0x00, 0x3A + "UserList", //0x00, 0x3B + "Validity", //0x00, 0x3C + "Value", //0x00, 0x3D + }; + + public static final String [] tagTablePage1 = { + /* Access ... continue on Page 0x0A */ + "AllFunctions", // 0x01, 0x05 + "AllFunctionsRequest", // 0x01, 0x06 + "CancelInvite-Request", // 0x01, 0x07 + "CancelInviteUser-Request", // 0x01, 0x08 + "Capability", // 0x01, 0x09 + "CapabilityList", // 0x01, 0x0A + "CapabilityRequest", // 0x01, 0x0B + "ClientCapability-Request", // 0x01, 0x0C + "ClientCapability-Response",// 0x01, 0x0D + "DigestBytes", // 0x01, 0x0E + "DigestSchema", // 0x01, 0x0F + "Disconnect", // 0x01, 0x10 + "Functions", // 0x01, 0x11 + "GetSPInfo-Request", // 0x01, 0x12 + "GetSPInfo-Response", // 0x01, 0x13 + "InviteID", // 0x01, 0x14 + "InviteNote", // 0x01, 0x15 + "Invite-Request", // 0x01, 0x16 + "Invite-Response", // 0x01, 0x17 + "InviteType", // 0x01, 0x18 + "InviteUser-Request", // 0x01, 0x19 + "InviteUser-Response", // 0x01, 0x1A + "KeepAlive-Request", // 0x01, 0x1B + "KeepAliveTime", // 0x01, 0x1C + "Login-Request", // 0x01, 0x1D + "Login-Response", // 0x01, 0x1E + "Logout-Request", // 0x01, 0x1F + "Nonce", // 0x01, 0x20 + "Password", // 0x01, 0x21 + "Polling-Request", // 0x01, 0x22 + "ResponseNote", // 0x01, 0x23 + "SearchElement", // 0x01, 0x24 + "SearchFindings", // 0x01, 0x25 + "SearchID", // 0x01, 0x26 + "SearchIndex", // 0x01, 0x27 + "SearchLimit", // 0x01, 0x28 + "KeepAlive-Response", // 0x01, 0x29 + "SearchPairList", // 0x01, 0x2A + "Search-Request", // 0x01, 0x2B + "Search-Response", // 0x01, 0x2C + "SearchResult", // 0x01, 0x2D + "Service-Request", // 0x01, 0x2E + "Service-Response", // 0x01, 0x2F + "SessionCookie", // 0x01, 0x30 + "StopSearch-Request", // 0x01, 0x31 + "TimeToLive", // 0x01, 0x32 + "SearchString", // 0x01, 0x33 + "CompletionFlag", // 0x01, 0x34 + null, // 0x01, 0x35 + "ReceiveList", // 0x01, 0x36 /* WV 1.2 */ + "VerifyID-Request", // 0x01, 0x37 /* WV 1.2 */ + "Extended-Request", // 0x01, 0x38 /* WV 1.2 */ + "Extended-Response", // 0x01, 0x39 /* WV 1.2 */ + "AgreedCapabilityList", // 0x01, 0x3A /* WV 1.2 */ + "Extended-Data", // 0x01, 0x3B /* WV 1.2 */ + "OtherServer", // 0x01, 0x3C /* WV 1.2 */ + "PresenceAttributeNSName",//0x01, 0x3D /* WV 1.2 */ + "SessionNSName", // 0x01, 0x3E /* WV 1.2 */ + "TransactionNSName", // 0x01, 0x3F /* WV 1.2 */ + }; + + public static final String [] tagTablePage2 = { + /* Service ... continue on Page 0x08 */ + "ADDGM", // 0x02, 0x05 + "AttListFunc", // 0x02, 0x06 + "BLENT", // 0x02, 0x07 + "CAAUT", // 0x02, 0x08 + "CAINV", // 0x02, 0x09 + "CALI", // 0x02, 0x0A + "CCLI", // 0x02, 0x0B + "ContListFunc", // 0x02, 0x0C + "CREAG", // 0x02, 0x0D + "DALI", // 0x02, 0x0E + "DCLI", // 0x02, 0x0F + "DELGR", // 0x02, 0x10 + "FundamentalFeat",//0x02, 0x11 + "FWMSG", // 0x02, 0x12 + "GALS", // 0x02, 0x13 + "GCLI", // 0x02, 0x14 + "GETGM", // 0x02, 0x15 + "GETGP", // 0x02, 0x16 + "GETLM", // 0x02, 0x17 + "GETM", // 0x02, 0x18 + "GETPR", // 0x02, 0x19 + "GETSPI", // 0x02, 0x1A + "GETWL", // 0x02, 0x1B + "GLBLU", // 0x02, 0x1C + "GRCHN", // 0x02, 0x1D + "GroupAuthFunc",// 0x02, 0x1E + "GroupFeat", // 0x02, 0x1F + "GroupMgmtFunc",// 0x02, 0x20 + "GroupUseFunc", // 0x02, 0x21 + "IMAuthFunc", // 0x02, 0x22 + "IMFeat", // 0x02, 0x23 + "IMReceiveFunc",// 0x02, 0x24 + "IMSendFunc", // 0x02, 0x25 + "INVIT", // 0x02, 0x26 + "InviteFunc", // 0x02, 0x27 + "MBRAC", // 0x02, 0x28 + "MCLS", // 0x02, 0x29 + "MDELIV", // 0x02, 0x2A + "NEWM", // 0x02, 0x2B + "NOTIF", // 0x02, 0x2C + "PresenceAuthFunc",//0x02, 0x2D + "PresenceDeliverFunc",//0x02, 0x2E + "PresenceFeat", // 0x02, 0x2F + "REACT", // 0x02, 0x30 + "REJCM", // 0x02, 0x31 + "REJEC", // 0x02, 0x32 + "RMVGM", // 0x02, 0x33 + "SearchFunc", // 0x02, 0x34 + "ServiceFunc", // 0x02, 0x35 + "SETD", // 0x02, 0x36 + "SETGP", // 0x02, 0x37 + "SRCH", // 0x02, 0x38 + "STSRC", // 0x02, 0x39 + "SUBGCN", // 0x02, 0x3A + "UPDPR", // 0x02, 0x3B + "WVCSPFeat", // 0x02, 0x3C + "MF", // 0x02, 0x3D /* WV 1.2 */ + "MG", // 0x02, 0x3E /* WV 1.2 */ + "MM" // 0x02, 0x3F /* WV 1.2 */ + }; + + public static final String [] tagTablePage3 = { + /* Client Capability */ + "AcceptedCharset", // 0x03, 0x05 + "AcceptedContentLength", // 0x03, 0x06 + "AcceptedContentType", // 0x03, 0x07 + "AcceptedTransferEncoding", // 0x03, 0x08 + "AnyContent", // 0x03, 0x09 + "DefaultLanguage", // 0x03, 0x0A + "InitialDeliveryMethod", // 0x03, 0x0B + "MultiTrans", // 0x03, 0x0C + "ParserSize", // 0x03, 0x0D + "ServerPollMin", // 0x03, 0x0E + "SupportedBearer", // 0x03, 0x0F + "SupportedCIRMethod", // 0x03, 0x10 + "TCPAddress", // 0x03, 0x11 + "TCPPort", // 0x03, 0x12 + "UDPPort" // 0x03, 0x13 + }; + + public static final String [] tagTablePage4 = { + /* Presence Primitive */ + "CancelAuth-Request", // 0x04, 0x05 + "ContactListProperties", // 0x04, 0x06 + "CreateAttributeList-Request", // 0x04, 0x07 + "CreateList-Request", // 0x04, 0x08 + "DefaultAttributeList", // 0x04, 0x09 + "DefaultContactList", // 0x04, 0x0A + "DefaultList", // 0x04, 0x0B + "DeleteAttributeList-Request", // 0x04, 0x0C + "DeleteList-Request", // 0x04, 0x0D + "GetAttributeList-Request", // 0x04, 0x0E + "GetAttributeList-Response", // 0x04, 0x0F + "GetList-Request", // 0x04, 0x10 + "GetList-Response", // 0x04, 0x11 + "GetPresence-Request", // 0x04, 0x12 + "GetPresence-Response", // 0x04, 0x13 + "GetWatcherList-Request", // 0x04, 0x14 + "GetWatcherList-Response", // 0x04, 0x15 + "ListManage-Request", // 0x04, 0x16 + "ListManage-Response", // 0x04, 0x17 + "UnsubscribePresence-Request", // 0x04, 0x18 + "PresenceAuth-Request", // 0x04, 0x19 + "PresenceAuth-User", // 0x04, 0x1A + "PresenceNotification-Request", // 0x04, 0x1B + "UpdatePresence-Request", // 0x04, 0x1C + "SubscribePresence-Request", // 0x04, 0x1D + "Auto-Subscribe", // 0x04, 0x1E /* WV 1.2 */ + "GetReactiveAuthStatus-Request",// 0x04, 0x1F /* WV 1.2 */ + "GetReactiveAuthStatus-Response",// 0x04, 0x20 /* WV 1.2 */ + }; + + public static final String [] tagTablePage5 = { + /* Presence Attribute */ + "Accuracy", // 0x05, 0x05 + "Address", // 0x05, 0x06 + "AddrPref", // 0x05, 0x07 + "Alias", // 0x05, 0x08 + "Altitude", // 0x05, 0x09 + "Building", // 0x05, 0x0A + "Caddr", // 0x05, 0x0B + "City", // 0x05, 0x0C + "ClientInfo", // 0x05, 0x0D + "ClientProducer", // 0x05, 0x0E + "ClientType", // 0x05, 0x0F + "ClientVersion", // 0x05, 0x10 + "CommC", // 0x05, 0x11 + "CommCap", // 0x05, 0x12 + "ContactInfo", // 0x05, 0x13 + "ContainedvCard", // 0x05, 0x14 + "Country", // 0x05, 0x15 + "Crossing1", // 0x05, 0x16 + "Crossing2", // 0x05, 0x17 + "DevManufacturer", // 0x05, 0x18 + "DirectContent", // 0x05, 0x19 + "FreeTextLocation", // 0x05, 0x1A + "GeoLocation", // 0x05, 0x1B + "Language", // 0x05, 0x1C + "Latitude", // 0x05, 0x1D + "Longitude", // 0x05, 0x1E + "Model", // 0x05, 0x1F + "NamedArea", // 0x05, 0x20 + "OnlineStatus", // 0x05, 0x21 + "PLMN", // 0x05, 0x22 + "PrefC", // 0x05, 0x23 + "PreferredContacts",// 0x05, 0x24 + "PreferredLanguage",// 0x05, 0x25 + "PreferredContent", // 0x05, 0x26 + "PreferredvCard", // 0x05, 0x27 + "Registration", // 0x05, 0x28 + "StatusContent", // 0x05, 0x29 + "StatusMood", // 0x05, 0x2A + "StatusText", // 0x05, 0x2B + "Street", // 0x05, 0x2C + "TimeZone", // 0x05, 0x2D + "UserAvailability", // 0x05, 0x2E + "Cap", // 0x05, 0x2F + "Cname", // 0x05, 0x30 + "Contact", // 0x05, 0x31 + "Cpriority", // 0x05, 0x32 + "Cstatus", // 0x05, 0x33 + "Note", // 0x05, 0x34 /* WV 1.2 */ + "Zone", // 0x05, 0x35 + null, + "Inf_link", // 0x05, 0x37 /* WV 1.2 */ + "InfoLink", // 0x05, 0x38 /* WV 1.2 */ + "Link", // 0x05, 0x39 /* WV 1.2 */ + "Text", // 0x05, 0x3A /* WV 1.2 */ + }; + + public static final String [] tagTablePage6 = { + /* Messaging */ + "BlockList", // 0x06, 0x05 +// "BlockUser-Request", // 0x06, 0x06 //This is a bug in the spec + "BlockEntity-Request", // 0x06, 0x06 + "DeliveryMethod", // 0x06, 0x07 + "DeliveryReport", // 0x06, 0x08 + "DeliveryReport-Request", // 0x06, 0x09 + "ForwardMessage-Request", // 0x06, 0x0A + "GetBlockedList-Request", // 0x06, 0x0B + "GetBlockedList-Response", // 0x06, 0x0C + "GetMessageList-Request", // 0x06, 0x0D + "GetMessageList-Response", // 0x06, 0x0E + "GetMessage-Request", // 0x06, 0x0F + "GetMessage-Response", // 0x06, 0x10 + "GrantList", // 0x06, 0x11 + "MessageDelivered", // 0x06, 0x12 + "MessageInfo", // 0x06, 0x13 + "MessageNotification", // 0x06, 0x14 + "NewMessage", // 0x06, 0x15 + "RejectMessage-Request", // 0x06, 0x16 + "SendMessage-Request", // 0x06, 0x17 + "SendMessage-Response", // 0x06, 0x18 + "SetDeliveryMethod-Request",// 0x06, 0x19 + "DeliveryTime", // 0x06, 0x1A + }; + + public static final String [] tagTablePage7 = { + /* Group */ + "AddGroupMembers-Request", // 0x07, 0x05 + "Admin", // 0x07, 0x06 + "CreateGroup-Request", // 0x07, 0x07 + "DeleteGroup-Request", // 0x07, 0x08 + "GetGroupMembers-Request", // 0x07, 0x09 + "GetGroupMembers-Response", // 0x07, 0x0A + "GetGroupProps-Request", // 0x07, 0x0B + "GetGroupProps-Response", // 0x07, 0x0C + "GroupChangeNotice", // 0x07, 0x0D + "GroupProperties", // 0x07, 0x0E + "Joined", // 0x07, 0x0F + "JoinedRequest", // 0x07, 0x10 + "JoinGroup-Request", // 0x07, 0x11 + "JoinGroup-Response", // 0x07, 0x12 + "LeaveGroup-Request", // 0x07, 0x13 + "LeaveGroup-Response", // 0x07, 0x14 + "Left", // 0x07, 0x15 + "MemberAccess-Request", // 0x07, 0x16 + "Mod", // 0x07, 0x17 + "OwnProperties", // 0x07, 0x18 + "RejectList-Request", // 0x07, 0x19 + "RejectList-Response", // 0x07, 0x1A + "RemoveGroupMembers-Request",// 0x07, 0x1B + "SetGroupProps-Request", // 0x07, 0x1C + "SubscribeGroupNotice-Request", // 0x07, 0x1D + "SubscribeGroupNotice-Response",// 0x07, 0x1E + "Users", // 0x07, 0x1F + "WelcomeNote", // 0x07, 0x20 + "JoinGroup", // 0x07, 0x21 + "SubscribeNotification", // 0x07, 0x22 + "SubscribeType", // 0x07, 0x23 + "GetJoinedUsers-Request", // 0x07, 0x24 /* WV 1.2 */ + "GetJoinedUsers-Response", // 0x07, 0x25 /* WV 1.2 */ + "AdminMapList", // 0x07, 0x26 /* WV 1.2 */ + "AdminMapping", // 0x07, 0x27 /* WV 1.2 */ + "Mapping", // 0x07, 0x28 /* WV 1.2 */ + "ModMapping", // 0x07, 0x29 /* WV 1.2 */ + "UserMapList", // 0x07, 0x2A /* WV 1.2 */ + "UserMapping", // 0x07, 0x2B /* WV 1.2 */ + }; + + public static final String [] tagTablePage8 = { + /* Service ... continued */ + "MP", // 0x08, 0x05 /* WV 1.2 */ + "GETAUT", // 0x08, 0x06 /* WV 1.2 */ + "GETJU", // 0x08, 0x07 /* WV 1.2 */ + "VRID", // 0x08, 0x08 /* WV 1.2 */ + "VerifyIDFunc", // 0x08, 0x09 /* WV 1.2 */ + }; + + public static final String [] tagTablePage9 = { + /* Common ... continued */ + "CIR", // 0x09, 0x05 /* WV 1.2 */ + "Domain", // 0x09, 0x06 /* WV 1.2 */ + "ExtBlock", // 0x09, 0x07 /* WV 1.2 */ + "HistoryPeriod", // 0x09, 0x08 /* WV 1.2 */ + "IDList", // 0x09, 0x09 /* WV 1.2 */ + "MaxWatcherList", // 0x09, 0x0A /* WV 1.2 */ + "ReactiveAuthState", // 0x09, 0x0B /* WV 1.2 */ + "ReactiveAuthStatus", // 0x09, 0x0C /* WV 1.2 */ + "ReactiveAuthStatusList", // 0x09, 0x0D /* WV 1.2 */ + "Watcher", // 0x09, 0x0E /* WV 1.2 */ + "WatcherStatus" // 0x09, 0x0F /* WV 1.2 */ + }; + + public static final String [] tagTablePageA = { + /* Access ... continued */ + "WV-CSP-NSDiscovery-Request", //0x0A, 0x05 /* WV 1.2 */ + "WV-CSP-NSDiscovery-Response", //0x0A, 0x06 /* WV 1.2 */ + "VersionList" //0x0A, 0x07 /* WV 1.2 */ + }; + + public static final String [] attrStartTable = { + "xmlns=http://www.wireless-village.org/CSP",// 0x00, 0x05 + "xmlns=http://www.wireless-village.org/PA", // 0x00, 0x06 + "xmlns=http://www.wireless-village.org/TRC",// 0x00, 0x07 + "xmlns=http://www.openmobilealliance.org/DTD/WV-CSP", // 0x00, 0x08 + "xmlns=http://www.openmobilealliance.org/DTD/WV-PA", // 0x00, 0x09 + "xmlns=http://www.openmobilealliance.org/DTD/WV-TRC", // 0x00, 0x0A + }; + + public static final String [] attrValueTable = { + + "AccessType", // 0x00 /* Common value token */ + "ActiveUsers", // 0x01 /* Common value token */ + "Admin", // 0x02 /* Common value token */ + "application/", // 0x03 /* Common value token */ + "application/vnd.wap.mms-message", // 0x04 /* Common value token */ + "application/x-sms", // 0x05 /* Common value token */ + "AutoJoin", // 0x06 /* Common value token */ + "BASE64", // 0x07 /* Common value token */ + "Closed", // 0x08 /* Common value token */ + "Default", // 0x09 /* Common value token */ + "DisplayName", // 0x0a /* Common value token */ + "F", // 0x0b /* Common value token */ + "G", // 0x0c /* Common value token */ + "GR", // 0x0d /* Common value token */ + "http://", // 0x0e /* Common value token */ + "https://", // 0x0f /* Common value token */ + "image/", // 0x10 /* Common value token */ + "Inband", // 0x11 /* Common value token */ + "IM", // 0x12 /* Common value token */ + "MaxActiveUsers", // 0x13 /* Common value token */ + "Mod", // 0x14 /* Common value token */ + "Name", // 0x15 /* Common value token */ + "None", // 0x16 /* Common value token */ + "N", // 0x17 /* Common value token */ + "Open", // 0x18 /* Common value token */ + "Outband", // 0x19 /* Common value token */ + "PR", // 0x1a /* Common value token */ + "Private", // 0x1b /* Common value token */ + "PrivateMessaging", // 0x1c /* Common value token */ + "PrivilegeLevel", // 0x1d /* Common value token */ + "Public", // 0x1e /* Common value token */ + "P", // 0x1f /* Common value token */ + "Request", // 0x20 /* Common value token */ + "Response", // 0x21 /* Common value token */ + "Restricted", // 0x22 /* Common value token */ + "ScreenName", // 0x23 /* Common value token */ + "Searchable", // 0x24 /* Common value token */ + "S", // 0x25 /* Common value token */ + "SC", // 0x26 /* Common value token */ + "text/", // 0x27 /* Common value token */ + "text/plain", // 0x28 /* Common value token */ + "text/x-vCalendar", // 0x29 /* Common value token */ + "text/x-vCard", // 0x2a /* Common value token */ + "Topic", // 0x2b /* Common value token */ + "T", // 0x2c /* Common value token */ + "Type", // 0x2d /* Common value token */ + "U", // 0x2e /* Common value token */ + "US", // 0x2f /* Common value token */ + "www.wireless-village.org", // 0x30 /* Common value token */ + "AutoDelete", // 0x31 /* Common value token */ /* WV 1.2 */ + "GM", // 0x32 /* Common value token */ /* WV 1.2 */ + "Validity", // 0x33 /* Common value token */ /* WV 1.2 */ + "ShowID", // 0x34 /* Common value token */ /* WV 1.2 */ + "GRANTED", // 0x35 /* Common value token */ /* WV 1.2 */ + "PENDING", // 0x36 /* Common value token */ /* WV 1.2 */ + null, // 0x37 + null, // 0x38 + null, // 0x39 + null, // 0x3a + null, // 0x3b + null, // 0x3c + "GROUP_ID", // 0x3d /* Access value token */ + "GROUP_NAME", // 0x3e /* Access value token */ + "GROUP_TOPIC", // 0x3f /* Access value token */ + "GROUP_USER_ID_JOINED", // 0x40 /* Access value token */ + "GROUP_USER_ID_OWNER", // 0x41 /* Access value token */ + "HTTP", // 0x42 /* Access value token */ + "SMS", // 0x43 /* Access value token */ + "STCP", // 0x44 /* Access value token */ + "SUDP", // 0x45 /* Access value token */ + "USER_ALIAS", // 0x46 /* Access value token */ + "USER_EMAIL_ADDRESS", // 0x47 /* Access value token */ + "USER_FIRST_NAME", // 0x48 /* Access value token */ + "USER_ID", // 0x49 /* Access value token */ + "USER_LAST_NAME", // 0x4a /* Access value token */ + "USER_MOBILE_NUMBER", // 0x4b /* Access value token */ + "USER_ONLINE_STATUS", // 0x4c /* Access value token */ + "WAPSMS", // 0x4d /* Access value token */ + "WAPUDP", // 0x4e /* Access value token */ + "WSP", // 0x4f /* Access value token */ + "GROUP_USER_ID_AUTOJOIN", // 0x50 /* Access value token */ /* WV 1.2 */ + null, // 0x51 + null, // 0x52 + null, // 0x53 + null, // 0x54 + null, // 0x55 + null, // 0x56 + null, // 0x57 + null, // 0x58 + null, // 0x59 + null, // 0x5a + "ANGRY", // 0x5b /* Presence value token */ + "ANXIOUS", // 0x5c /* Presence value token */ + "ASHAMED", // 0x5d /* Presence value token */ + "AUDIO_CALL", // 0x5e /* Presence value token */ + "AVAILABLE", // 0x5f /* Presence value token */ + "BORED", // 0x60 /* Presence value token */ + "CALL", // 0x61 /* Presence value token */ + "CLI", // 0x62 /* Presence value token */ + "COMPUTER", // 0x63 /* Presence value token */ + "DISCREET", // 0x64 /* Presence value token */ + "EMAIL", // 0x65 /* Presence value token */ + "EXCITED", // 0x66 /* Presence value token */ + "HAPPY", // 0x67 /* Presence value token */ + "IM", // 0x68 /* Presence value token */ + "IM_OFFLINE", // 0x69 /* Presence value token */ + "IM_ONLINE", // 0x6a /* Presence value token */ + "IN_LOVE", // 0x6b /* Presence value token */ + "INVINCIBLE", // 0x6c /* Presence value token */ + "JEALOUS", // 0x6d /* Presence value token */ + "MMS", // 0x6e /* Presence value token */ + "MOBILE_PHONE", // 0x6f /* Presence value token */ + "NOT_AVAILABLE", // 0x70 /* Presence value token */ + "OTHER", // 0x71 /* Presence value token */ + "PDA", // 0x72 /* Presence value token */ + "SAD", // 0x73 /* Presence value token */ + "SLEEPY", // 0x74 /* Presence value token */ + "SMS", // 0x75 /* Presence value token */ + "VIDEO_CALL", // 0x76 /* Presence value token */ + "VIDEO_STREAM", // 0x77 /* Presence value token */ + }; + + +} |