📄 wbxmlwriter.java
字号:
/* kXML
*
* The contents of this file are subject to the Enhydra Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License
* on the Enhydra web site ( http://www.enhydra.org/ ).
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific terms governing rights and limitations
* under the License.
*
* The Initial Developer of kXML is Stefan Haustein. Copyright (C)
* 2000, 2001 Stefan Haustein, D-46045 Oberhausen (Rhld.),
* Germany. All Rights Reserved.
*
* Contributor(s): Paul Palaszewski, Michael Wallbaum, Nicola Fankhauser
*
* */
package org.kxml.wap;
import java.io.*;
import java.util.*;
import org.kxml.*;
import org.kxml.io.*;
/**
* A class for converting ("binary encoding") XML to WBXML.
* Todo:
* <ul>
* <li>Add support for processing instructions
* <li>Add support for WBXML extensions
* </ul>
* @author Stefan Haustein, Paul Palaszewski, Michael Wallbaum, Nicola Fankhauser
* @version $Id: WbxmlWriter.java,v 1.4 2003/07/19 16:28:27 stefano_fornari Exp $
*/
public class WbxmlWriter extends AbstractXmlWriter {
Hashtable stringTable = new Hashtable();
OutputStream out;
ByteArrayOutputStream buf = new ByteArrayOutputStream();
ByteArrayOutputStream stringTableBuf = new ByteArrayOutputStream();
String pending;
Vector attributes = new Vector();
Hashtable attrStartTable = new Hashtable();
Hashtable attrValueTable = new Hashtable();
Hashtable tagTable = new Hashtable();
int currentPage = 0;
Hashtable otherAttrStartTables = new Hashtable();
Hashtable otherAttrValueTables = new Hashtable();
Hashtable otherTagTables = new Hashtable();
public WbxmlWriter(OutputStream out) throws IOException {
this.out = out;
buf = new ByteArrayOutputStream();
stringTableBuf = new ByteArrayOutputStream();
}
/** ATTENTION: flush cannot work since Wbxml documents cannot
* need buffering. Thus, this call does nothing. */
public void flush() {
}
/**
* Writes out the whole WBXML stream.
*
* @exception IOException if an error occurs while writing
*/
public void close() throws IOException {
writeHeader();
writeInt(out, stringTableBuf.size());
out.write(stringTableBuf.toByteArray());
out.write(buf.toByteArray());
out.flush(); // ready!
}
/**
* Writes out WBXML headers, override for other behaviour / values
*
* @exception IOException if an error occurs while writing
*/
void writeHeader() throws IOException {
out.write(Wbxml.WBXML_VERSION_12 ); // version
out.write(Wbxml.WBXML_PUBLICID ); // public identifier
out.write(Wbxml.WBXML_CHARSET_UTF8); // iso-8859-1
}
/**
* Searches in all available code pages for a certain token. If it finds
* a page, it switches to it and returns the index for the token. If no suiting page
* is found, <code>null</code> is returned.
*
* @param pending the token to search for
* @param table the table to search through for token
* @return the index of the token or null (if not found)
*/
private Integer searchToken(String pending, Hashtable table){
Integer idx = null;
for (Enumeration e = table.keys() ; e.hasMoreElements() ;) {
Integer page = (Integer) e.nextElement();
Hashtable h = (Hashtable) table.get(page);
idx = (Integer) h.get(pending);
if(idx != null){
switchPage(page);
break;
}
}
return idx;
}
/**
* Switches page, sets all arrays accordingly and writes out the WBXML <code>SWITCH_PAGE</code>
* token
*
* @param page which page to switch to
*/
private void switchPage(Integer page) {
this.currentPage = page.intValue();
tagTable = (Hashtable) otherTagTables.get(page);
attrStartTable = (Hashtable) otherAttrStartTables.get(page);
attrValueTable = (Hashtable) otherAttrValueTables.get(page);
// make sure that after switch every token table is at least an empty hashtable, and not null
if(tagTable == null) { tagTable = new Hashtable(); }
if(attrStartTable == null) { attrStartTable = new Hashtable(); }
if(attrValueTable == null) { attrValueTable = new Hashtable(); }
buf.write(Wbxml.SWITCH_PAGE);
buf.write(page.intValue());
}
public void checkPending(boolean degenerated) throws IOException {
if (pending == null) return;
int len = attributes.size();
Integer idx = (Integer) tagTable.get(pending);
if(idx == null) {
idx = searchToken(pending, otherTagTables);
}
// 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 {
buf.write
(len == 0
? (degenerated ? idx.intValue() : idx.intValue() | 64 )
: (degenerated ? idx.intValue() | 128 : idx.intValue() | 192 ));
}
for (int i = 0; i < len;i++) {
idx = (Integer) attrStartTable.get(attributes.elementAt(i));
if(idx == null) {
idx = searchToken((String) attributes.elementAt(i), otherAttrStartTables);
}
if(idx == null) {
buf.write(Wbxml.LITERAL);
writeStrT((String) attributes.elementAt(i));
} else {
buf.write(idx.intValue());
}
idx = (Integer) attrValueTable.get(attributes.elementAt(++i));
if(idx == null) {
idx = searchToken((String) attributes.elementAt(i), otherAttrValueTables);
}
if(idx == null) {
buf.write(Wbxml.STR_I);
writeStrI(buf, (String) attributes.elementAt(i));
} else {
buf.write(idx.intValue());
}
}
if (len > 0) {
buf.write(Wbxml.END);
}
pending = null;
attributes.removeAllElements();
}
public void startTag(PrefixMap prefixMap,
String name) throws IOException {
current = new State(current, prefixMap, name);
checkPending(false);
pending = name;
}
public void attribute(String name, String value) {
attributes.addElement(name);
attributes.addElement(value);
}
public void write(char [] chars, int start, int len) throws IOException {
write(chars, start, len, false);
}
public void write(char [] chars,
int start, int len, boolean opaque) throws IOException {
checkPending(false);
if (opaque) {
buf.write(Wbxml.OPAQUE);
writeInt(buf, len);
writeOpaque(buf, chars, start, len);
} else {
buf.write(Wbxml.STR_I);
writeStrI(buf, new String(chars, start, len));
}
}
public void endTag() throws IOException {
current = current.prev;
if (pending != null)
checkPending(true);
else
buf.write(Wbxml.END);
}
/** 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);
}
static void writeOpaque(OutputStream out, char[] chars, int start, int length) throws IOException {
for (int i=start; i < length; i++) {
out.write((byte)chars[i]);
}
}
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());
}
/**
* Copies a user-given token-<code>table</code> with given <code>offset</code> into a hashtable
* and inserts this hashtable into the <code>otherTables</code> with
* <code>page</code> as key.
*
* @param table user-given array with tokens
* @param offset where to locate the tokens regarding the conversion to WBXML
* @param page which code page to change
* @param otherTables where to store the newly created hashtable with the tokens (for page switches)
* @return returns a <code>Hashtable</code> with tokens
*/
private Hashtable processTable(String[] table, int offset, int page, Hashtable otherTables) {
Hashtable h = new Hashtable();
// fill up the new hashtable
for(int i=0;i < table.length;i++) {
if(table[i] != null) {
Integer idx = new Integer(i+offset);
h.put(table[i],idx);
}
}
// save the new hashtable
otherTables.put(new Integer(page),h);
return h;
}
/**
* Sets the tag table for a given page.
* The first string in the array defines tag 5, the second tag 6 etc.
*
* @param page the code page the token table refers to
* @param tagTable a table filled with tokens
*/
public void setTagTable(int page, String [] tagTable) {
Hashtable temp = processTable(tagTable, 5, page, otherTagTables);
if(page == 0) {
this.tagTable = temp;
}
}
/**
* 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
*
* @param page the code page the token table refers to
* @param attrStartTable a table filled with tokens
*/
public void setAttrStartTable(int page, String [] attrStartTable) {
Hashtable temp = processTable(attrStartTable, 5, page, otherAttrStartTables);
if(page == 0) {
this.attrStartTable = temp;
}
}
/**
* 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.
*
* @param page the code page the token table refers to
* @param attrValueTable a table filled with tokens
*/
public void setAttrValueTable(int page, String [] attrValueTable) {
Hashtable temp = processTable(attrValueTable, 0x85, page, otherAttrValueTables);
if(page == 0) {
this.attrValueTable = temp;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -