FileDocCategorySizeDatePackage
WbxmlParser.javaAPI DocAndroid 1.5 API31163Wed May 06 22:41:06 BST 2009org.kxml2.wap

WbxmlParser

public class WbxmlParser extends Object implements XmlPullParser

Fields Summary
static final String
HEX_DIGITS
public static final int
WAP_EXTENSION
Parser event type for Wbxml-specific events. The Wbxml event code can be accessed with getWapCode()
private static final String
UNEXPECTED_EOF
private static final String
ILLEGAL_TYPE
private InputStream
in
private int
TAG_TABLE
private int
ATTR_START_TABLE
private int
ATTR_VALUE_TABLE
private String[]
attrStartTable
private String[]
attrValueTable
private String[]
tagTable
private byte[]
stringTable
private Hashtable
cacheStringTable
private boolean
processNsp
private int
depth
private String[]
elementStack
private String[]
nspStack
private int[]
nspCounts
private int
attributeCount
private String[]
attributes
private int
nextId
private Vector
tables
private int
version
private int
publicIdentifierId
private String
prefix
private String
namespace
private String
name
private String
text
private Object
wapExtensionData
private int
wapCode
private int
type
private boolean
degenerated
private boolean
isWhitespace
private String
encoding
Constructors Summary
Methods Summary
private final booleanadjustNsp()

        
        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;
    
public voiddefineEntityReplacementText(java.lang.String entity, java.lang.String value)

        
        // just ignore, has no effect
    
private final java.lang.String[]ensureCapacity(java.lang.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 voidexception(java.lang.String desc)

        throw new XmlPullParserException(desc, this, null);
    
public intgetAttributeCount()

        return attributeCount;
    
public java.lang.StringgetAttributeName(int index)

        if (index >= attributeCount)
            throw new IndexOutOfBoundsException();
        return attributes[(index << 2) + 2];
    
public java.lang.StringgetAttributeNamespace(int index)

        if (index >= attributeCount)
            throw new IndexOutOfBoundsException();
        return attributes[index << 2];
    
public java.lang.StringgetAttributePrefix(int index)

        if (index >= attributeCount)
            throw new IndexOutOfBoundsException();
        return attributes[(index << 2) + 1];
    
public java.lang.StringgetAttributeType(int index)

        return "CDATA";
    
public java.lang.StringgetAttributeValue(int index)

        if (index >= attributeCount)
            throw new IndexOutOfBoundsException();
        return attributes[(index << 2) + 3];
    
public java.lang.StringgetAttributeValue(java.lang.String namespace, java.lang.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 intgetColumnNumber()

        return -1;
    
public intgetDepth()

        return depth;
    
public intgetEventType()

        return type;
    
public booleangetFeature(java.lang.String feature)

    
        
        if (XmlPullParser
        .FEATURE_PROCESS_NAMESPACES
        .equals(feature))
            return processNsp;
        else
            return false;
    
public java.lang.StringgetInputEncoding()

        return encoding;
    
public intgetLineNumber()

        return -1;
    
public java.lang.StringgetName()

        return name;
    
public java.lang.StringgetNamespace()

        return namespace;
    
public java.lang.StringgetNamespace(java.lang.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 intgetNamespaceCount(int depth)

        if (depth > this.depth)
            throw new IndexOutOfBoundsException();
        return nspCounts[depth];
    
public java.lang.StringgetNamespacePrefix(int pos)

        return nspStack[pos << 1];
    
public java.lang.StringgetNamespaceUri(int pos)

        return nspStack[(pos << 1) + 1];
    
public java.lang.StringgetPositionDescription()

        
        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 java.lang.StringgetPrefix()

        return prefix;
    
public java.lang.ObjectgetProperty(java.lang.String property)

        return null;
    
public java.lang.StringgetText()

        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 intgetWapCode()
Returns the token ID for start tags or the event type for wap proprietary events such as OPAQUE.

        return wapCode;
    
public java.lang.ObjectgetWapExtensionData()

        return wapExtensionData;
    
public booleanisAttributeDefault(int index)

        return false;
    
public booleanisEmptyElementTag()

        if (type != START_TAG)
            exception(ILLEGAL_TYPE);
        return degenerated;
    
public booleanisWhitespace()

        if (type != TEXT
        && type != IGNORABLE_WHITESPACE
        && type != CDSECT)
            exception(ILLEGAL_TYPE);
        return isWhitespace;
    
public intnext()

        
        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.STR_T:
                    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;
    
private final voidnextImpl()

        
        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 :
                
                type = WAP_EXTENSION;
                wapCode = id;
                wapExtensionData = 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 intnextTag()

        
        next();
        if (type == TEXT && isWhitespace)
            next();
        
        if (type != END_TAG && type != START_TAG)
            exception("unexpected type");
        
        return type;
    
public java.lang.StringnextText()

        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 intnextToken()

        
        isWhitespace = true;
        nextImpl();
        return type;
    
voidparseElement(int id)

        
        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;
        
    
public java.lang.ObjectparseWapExtension(int id)
Overwrite this method to intercept all wap events

        
        switch (id) {
            case Wbxml.EXT_I_0 :
            case Wbxml.EXT_I_1 :
            case Wbxml.EXT_I_2 :
                return readStrI();
                
            case Wbxml.EXT_T_0 :
            case Wbxml.EXT_T_1 :
            case Wbxml.EXT_T_2 :
                return new Integer(readInt());
                
            case Wbxml.EXT_0 :
            case Wbxml.EXT_1 :
            case Wbxml.EXT_2 :
                return null;
                
            case Wbxml.OPAQUE : 
            {
                int count = readInt();
                byte[] buf = new byte[count];
                
                while(count > 0){
                    count -= in.read(buf, buf.length-count, count);
                }
                
                return buf;
            } // case OPAQUE
    
            
            default:
                exception("illegal id: "+id);
                return null; // dead code
        } // SWITCH
    
private intpeekId()

        if (nextId == -2) {
            nextId = in.read ();
        }
        return nextId;
    
public voidreadAttr()

        
        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 :
                        value.append(resolveWapExtension(id, parseWapExtension(id)));
                        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++;
        }
    
intreadByte()

        int i = in.read();
        if (i == -1)
            throw new IOException("Unexpected EOF");
        return i;
    
intreadInt()

        int result = 0;
        int i;
        
        do {
            i = readByte();
            result = (result << 7) | (i & 0x7f);
        }
        while ((i & 0x80) != 0);
        
        return result;
    
java.lang.StringreadStrI()

        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;
    
java.lang.StringreadStrT()

        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;
    
public voidrequire(int type, java.lang.String namespace, java.lang.String name)

        
        if (type != this.type
        || (namespace != null && !namespace.equals(getNamespace()))
        || (name != null && !name.equals(getName())))
            exception(
            "expected: " + (type == WAP_EXTENSION ? "WAP Ext." : (TYPES[type] + " {" + namespace + "}" + name)));
    
java.lang.StringresolveId(java.lang.String[] tab, int id)

        int idx = (id & 0x07f) - 5;
        if (idx == -1){
            wapCode = -1;
            return readStrT();
        }
        if (idx < 0
        || tab == null
        || idx >= tab.length
        || tab[idx] == null)
            throw new IOException("id " + id + " undef.");
        
        wapCode = idx+5;
        
        return tab[idx];
    
protected java.lang.StringresolveWapExtension(int id, java.lang.Object data)
overwrite for own WAP extension handling in attributes and high level parsing (above nextToken() level)

        
        if(data instanceof byte[]){
            StringBuffer sb = new StringBuffer();
            byte[] b = (byte[]) data;
            
            for (int i = 0; i < b.length; i++) {
                sb.append(HEX_DIGITS.charAt((b[i] >> 4) & 0x0f));
                sb.append(HEX_DIGITS.charAt(b[i] & 0x0f));
            }
            return sb.toString();
        }

        return "$("+data+")";
    
private voidselectPage(int nr, boolean tags)

        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);
        }
    
public voidsetAttrStartTable(int page, java.lang.String[] table)
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

        
        setTable(page, ATTR_START_TABLE, table);
    
public voidsetAttrValueTable(int page, java.lang.String[] 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.

        
        setTable(page, ATTR_VALUE_TABLE, table);
    
public voidsetFeature(java.lang.String feature, boolean value)

        if (XmlPullParser.FEATURE_PROCESS_NAMESPACES.equals(feature))
            processNsp = value;
        else
            exception("unsupported feature: " + feature);
    
public voidsetInput(java.io.Reader reader)

        exception("InputStream required");
    
public voidsetInput(java.io.InputStream in, java.lang.String enc)

        
        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 voidsetProperty(java.lang.String property, java.lang.Object value)

        throw new XmlPullParserException("unsupported property: " + property);
    
private final voidsetTable(int page, int type, java.lang.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);
    
public voidsetTagTable(int page, java.lang.String[] table)
Sets the tag table for a given page. The first string in the array defines tag 5, the second tag 6 etc.

        setTable(page, TAG_TABLE, table);
        
        //        this.tagTable = tagTable;
        //      if (page != 0)
        //        throw new RuntimeException("code pages curr. not supp.");