⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wbxmldecoder.java

📁 WAP协议栈的JAVA实现
💻 JAVA
字号:
/**
 * JWAP - A Java Implementation of the WAP Protocols
 * Copyright (C) 2001-2004 Niko Bender
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
package net.sourceforge.jwap.util.wbxml;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;


/**
 * to do's :- string table length is in multiple byte format, currently it is assumed to be single byte
 * index in string table should also be read as multiple byte format
 * character encoding supported is only utf-8, for other encodings the termination character in string table can be different...
 * @author suvarna
 */
public class WBXMLDecoder {
    private static WBXMLDecoder instance;
    private DataInputStream wbxmlStream;
    private Document xmlDocument;
    private String publicId;
    private StringBuffer stringTable;
    private byte parentBitMask = (byte) 0x40;

    // The bit representation 10000000
    private byte attributeBitMask = (byte) 0x80;

    private WBXMLDecoder() {
        initialize();
    }

    // The bit representation 01000000
    public static WBXMLDecoder getInstance() {
        if (instance == null) {
            instance = new WBXMLDecoder();
        }

        return instance;
    }

    private void initialize() {
    }

    public Document decode(InputStream wbxmlStream) {
        this.wbxmlStream = new DataInputStream(wbxmlStream);

        try {
            xmlDocument = DocumentBuilderFactory.newInstance()
                                                .newDocumentBuilder()
                                                .newDocument();
            decodeProlog();
            decodeBody();
        } catch (Exception exp) {
            exp.printStackTrace();
        }

        return xmlDocument;
    }

    /**
     *  currently encoding cannot be specifies as DOM does not have any API to access the XML declaration.
     * by default utf-16 is used.. If encoding is to be used ...
     * xmlDocument.getImplementation().String piData = "version=\"1.0\" encoding=\"" + encoding + "\"";
     * ProcessingInstruction xmlDeclaration = xmlDocument.createProcessingInstruction("xml", piData);
     * xmlDocument.insertBefore(xmlDeclaration, xmlDocument.getDocumentElement());
     **/
    private void decodeProlog() throws IOException {
        byte version = wbxmlStream.readByte();

        //	int publicIdValue = wbxmlStream.readInt(); // AS IT IS MULTIPLE BYTE
        byte publicIdValue = wbxmlStream.readByte();

        // to do for  MULTIPLE BYTE
        publicId = PublicIdentifiers.getInstance().getPublicIdentifier(publicIdValue);

        //		int charset = wbxmlStream.readInt();
        int charset = wbxmlStream.readByte(); // to do for mutiple byte
        String encoding = IANACharSet.getEncoding(charset);

        //		int strtblSize = wbxmlStream.readInt();
        byte strtblSize = wbxmlStream.readByte();

        // to do for multiple bytes and negative size
        stringTable = new StringBuffer(strtblSize);

        for (int i = 0; i < strtblSize; i++)
            stringTable.append((char) wbxmlStream.readByte());
    }

    private void decodeBody() throws IOException {
        writeRootElement();
    }

    private void writeRootElement() throws IOException {
        byte maskedTokenValue = wbxmlStream.readByte();
        byte actualTokenValue = getTokenValue(maskedTokenValue);
        String rootElementName = TokenRepository.getInstance().getTagName(actualTokenValue);

        try {
            DocumentBuilder builder = DocumentBuilderFactory.newInstance()
                                                            .newDocumentBuilder();
            String systemId = PublicIdentifiers.getInstance()
                                               .getSystemIdentifier(publicId);

            /*                DocumentType docType =
                                    builder.getDOMImplementation().createDocumentType(
                                            rootElementName,
                                            publicId,
                                            systemId);
            */
            xmlDocument = builder.getDOMImplementation().createDocument("",
                    rootElementName, null);

            if (hasAttributes(maskedTokenValue)) {
                setAttributes(xmlDocument.getDocumentElement());
            }

            if (hasContent(maskedTokenValue)) {
                writeChildElement(xmlDocument.getDocumentElement());
            }
        } catch (Exception exp) {
            exp.printStackTrace();
        }
    }

    private void writeChildElement(Element parent) throws IOException {
        byte maskedTokenValue = wbxmlStream.readByte();

        while (maskedTokenValue != 01) { // END (of parent element)

            byte actualTokenValue = getTokenValue(maskedTokenValue);

            if (isInlineStrToken(actualTokenValue)) { // element has text content
                writeContentAsInlineStr(parent);
            } else {
                if (isEntityToken(actualTokenValue)) { // element has entity
                    writeEntityContent(parent);
                } else if (isStringTableReferenceToken(maskedTokenValue)) {
                    byte indexInStringTable = wbxmlStream.readByte();
                    writeContentFromStrTable(parent, indexInStringTable);
                } else {
                    String elementName = TokenRepository.getInstance()
                                                        .getTagName(actualTokenValue);
                    System.out.println("element name" + elementName);

                    Element childElement = xmlDocument.createElement(elementName);
                    parent.appendChild(childElement);

                    if (hasAttributes(maskedTokenValue)) {
                        setAttributes(childElement);
                    }

                    if (hasContent(maskedTokenValue)) {
                        writeChildElement(childElement);
                        maskedTokenValue = wbxmlStream.readByte();

                        continue;
                    }
                }
            }

            maskedTokenValue = wbxmlStream.readByte();
        }
    }

    private void writeContentFromStrTable(Element parent, int indexInStringTable) {
        char c = 0x0;
        int endIndex = stringTable.toString().indexOf(new String(new char[] { c }),
                indexInStringTable);
        String content = stringTable.substring(indexInStringTable, endIndex);
        Text txtContent = xmlDocument.createTextNode(content);
        parent.appendChild(txtContent);
    }

    private boolean hasAttributes(byte tokenValue) {
        //		System.out.println(tokenValue);
        //		System.out.println(attributeBitMask);
        //		boolean ans =(tokenValue & attributeBitMask) == attributeBitMask;
        return ((tokenValue & attributeBitMask) == attributeBitMask);
    }

    private boolean hasContent(byte tokenValue) {
        return (tokenValue & parentBitMask) == parentBitMask;
    }

    private void setAttributes(Element element) throws IOException {
        byte attrTokenValue = wbxmlStream.readByte();
        String currentAttrName = "";

        while (attrTokenValue != 01) { // END (of attribue list)

            if (isInlineStrToken(attrTokenValue)) {
                writeInlineStrAttrValue(element, currentAttrName);
            } else {
                if (isEntityToken(attrTokenValue)) {
                    writeEntityAsAttribute(element, currentAttrName);
                } else if (isStringTableReferenceToken(attrTokenValue)) {
                    byte indexInStringTable = wbxmlStream.readByte();
                    writeAttributeFromStrTable(element, currentAttrName,
                        indexInStringTable);
                } else {
                    if (isAttrNameToken(attrTokenValue)) {
                        currentAttrName = writeAttribute(element, attrTokenValue);
                    } else {
                        if (isAttrValueToken(attrTokenValue)) {
                            writeAttrValue(element, currentAttrName,
                                attrTokenValue);
                        }
                    }
                }
            }

            attrTokenValue = wbxmlStream.readByte();
        }
    }

    private String writeAttribute(Element element, byte attrTokenValue) {
        String[] attributeNameAndPrefix = TokenRepository.getInstance()
                                                         .getAttributeNameAndPrefix(attrTokenValue);
        String attributeValue = "";
        String attributeName = attributeNameAndPrefix[0].toString();
        boolean hasPrefix = attributeNameAndPrefix[1] != null;

        if (hasPrefix) {
            attributeValue = attributeNameAndPrefix[1].trim();
        }

        Attr attrNode = xmlDocument.createAttribute(attributeName);
        attrNode.setValue(attributeValue);
        element.setAttributeNode(attrNode);

        return attributeName;
    }

    private void writeAttrValue(Element element, String attrName,
        byte attrTokenValue) throws IOException {
        String partialAttrValue = element.getAttribute(attrName);
        String attrValue = partialAttrValue +
            TokenRepository.getInstance().getAttributeValue(attrTokenValue);
        element.setAttribute(attrName, attrValue);
    }

    private void writeAttributeFromStrTable(Element element, String attrName,
        byte indexInStringTable) {
        String partialAttrValue = element.getAttribute(attrName);
        char c = 0x0;
        int endIndex = stringTable.toString().indexOf(new String(new char[] { c }),
                indexInStringTable);
        String attrValue = partialAttrValue +
            stringTable.substring(indexInStringTable, endIndex);
        element.setAttribute(attrName, attrValue);
    }

    private void writeInlineStrAttrValue(Element element, String attrName)
        throws IOException {
        String previous_value = element.getAttribute(attrName);
        StringBuffer attrValue = new StringBuffer(previous_value.equals("null")
                ? "" : previous_value);
        byte aChar = wbxmlStream.readByte();

        while (aChar != 00) {
            attrValue.append((char) aChar);
            aChar = wbxmlStream.readByte();
        }

        element.setAttribute(attrName, attrValue.toString());
    }

    private void writeEntityAsAttribute(Element element, String attrName)
        throws IOException {
        String previous_value = element.getAttribute(attrName);
        StringBuffer attrValue = new StringBuffer(previous_value.equals("null")
                ? "" : previous_value);

        byte aChar = wbxmlStream.readByte();

        while ((aChar & (byte) 0x80) == 0x80) {
            // is aChar's continuation flag(MSB) is on)
            aChar = (byte) (aChar & 0x7f); //extract remaining 7 bits;

            String str1 = Integer.toString(aChar, 2);
            attrValue.append(str1);
            aChar = wbxmlStream.readByte();
        }

        String str2 = Integer.toString(aChar, 2);

        // last byte in multiple byte format
        while (str2.length() < 7)
            str2 = "0" + str2;

        attrValue.append(str2);

        int multipleByteValue = Integer.parseInt(attrValue.toString(), 2);
        System.out.println("entity as attrribute value " + multipleByteValue);
        element.setAttribute(attrName, "&#" + multipleByteValue + ";");
    }

    private void writeContentAsInlineStr(Element element)
        throws IOException {
        StringBuffer attrValue = new StringBuffer();
        byte aChar = wbxmlStream.readByte();

        while (aChar != 00) {
            attrValue.append((char) aChar);
            aChar = wbxmlStream.readByte();
        }

        Text txtContent = xmlDocument.createTextNode(attrValue.toString());
        element.appendChild(txtContent);
    }

    private boolean isEntityToken(byte tokenValue) {
        return tokenValue == GlobalTokens.ENTITY;

        // todo for other global tokens
    }

    private boolean isStringTableReferenceToken(byte tokenValue) {
        return tokenValue == GlobalTokens.STR_T;
    }

    private void writeEntityContent(Element element) throws IOException {
        StringBuffer attrValue = new StringBuffer();
        byte aChar = wbxmlStream.readByte();

        while ((aChar & (byte) 0x80) == 0x80) {
            // is aChar's continuation flag(MSB) is on)
            aChar = (byte) (aChar & 0x7f); //extract remaining 7 bits;

            String str1 = Integer.toString(aChar, 2);
            attrValue.append(str1);
            aChar = wbxmlStream.readByte();
        }

        String str2 = Integer.toString(aChar, 2);

        // last byte in multiple byte format
        while (str2.length() < 7)
            str2 = "0" + str2;

        attrValue.append(str2);

        int multipleByteValue = Integer.parseInt(attrValue.toString(), 2);
        System.out.println(multipleByteValue);

        Text txtContent = xmlDocument.createTextNode(Integer.toString(
                    multipleByteValue));
        element.appendChild(txtContent);
    }

    private boolean isInlineStrToken(byte tokenValue) {
        return tokenValue == GlobalTokens.STR_ISTR_I;
    }

    private boolean isAttrNameToken(byte tokenValue) {
        return (tokenValue >= 0);
    }

    private boolean isAttrValueToken(byte tokenValue) {
        return (tokenValue < 0);
    }

    private byte getTokenValue(byte maskedTokenValue) {
        byte unmaskedTokenValue = (byte) (maskedTokenValue & ((byte) 0x3f));

        // 3f =~ 0011 1111
        return unmaskedTokenValue;
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -