📄 wbxmldecoder.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 + -