Bring our kxml2 up to date with upstream.
Much of this is spurious whitespace changes, but there's some increased
"relaxation". I deliberately lost the Android-specific change that was
avoiding Runtime, since we do now have Runtime. I've added an Android-specific
change to comment out some System.out logging that's been added upstream.
I'd tell you the upstream revision number, but they're still using CVS, so
there isn't one.
diff --git a/xml/src/main/java/org/kxml2/io/KXmlParser.java b/xml/src/main/java/org/kxml2/io/KXmlParser.java
index 0727bc7..98aae04 100644
--- a/xml/src/main/java/org/kxml2/io/KXmlParser.java
+++ b/xml/src/main/java/org/kxml2/io/KXmlParser.java
@@ -33,7 +33,7 @@
public class KXmlParser implements XmlPullParser {
private Object location;
- static final private String UNEXPECTED_EOF = "Unexpected EOF";
+ 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;
@@ -65,13 +65,14 @@
// txtbuffer
+ /** Target buffer for storing incoming text (including aggregated resolved entities) */
private char[] txtBuf = new char[128];
+ /** Write position */
private int txtPos;
// Event-related
private int type;
- //private String text;
private boolean isWhitespace;
private String namespace;
private String prefix;
@@ -80,7 +81,7 @@
private boolean degenerated;
private int attributeCount;
private String[] attributes = new String[16];
- private int stackMismatch = 0;
+// private int stackMismatch = 0;
private String error;
/**
@@ -95,12 +96,8 @@
private boolean token;
public KXmlParser() {
- // BEGIN android-changed
- // We don't have a Runtime class at this time.
- // srcBuf =
- // new char[Runtime.getRuntime().freeMemory() >= 1048576 ? 8192 : 128];
- srcBuf = new char[8192];
- // END android-changed
+ srcBuf =
+ new char[Runtime.getRuntime().freeMemory() >= 1048576 ? 8192 : 128];
}
private final boolean isProp(String n1, boolean prop, String n2) {
@@ -263,39 +260,39 @@
while (true) {
attributeCount = -1;
- // degenerated needs to be handled before error because of possible
- // processor expectations(!)
+ // degenerated needs to be handled before error because of possible
+ // processor expectations(!)
- if (degenerated) {
- degenerated = false;
- type = END_TAG;
- return;
- }
+ 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;
+ // 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;
- }
+// 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;
@@ -327,7 +324,7 @@
if (isWhitespace)
type = IGNORABLE_WHITESPACE;
// make exception switchable for instances.chg... !!!!
- // else
+ // else
// exception ("text '"+getText ()+"' not allowed outside root element");
}
return;
@@ -458,7 +455,7 @@
prev = c;
}
- if (term == '-' && prev == '-')
+ if (term == '-' && prev == '-' && !relaxed)
error("illegal comment delimiter: --->");
read();
@@ -529,28 +526,30 @@
return;
}
- if (!name.equals(elementStack[sp + 3])) {
+ if (!relaxed) {
+ if (!name.equals(elementStack[sp + 3])) {
error("expected: /" + elementStack[sp + 3] + " read: " + name);
- // become case insensitive in relaxed mode
+ // 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;
- }
+// 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 {
@@ -661,8 +660,10 @@
skip();
if (peek(0) != '=') {
- error("Attr.value missing f. "+attrName);
- attributes[i] = "1";
+ if(!relaxed){
+ error("Attr.value missing f. "+attrName);
+ }
+ attributes[i] = attrName;
}
else {
read('=');
@@ -670,12 +671,14 @@
int delimiter = peek(0);
if (delimiter != '\'' && delimiter != '"') {
- error("attr value delimiter missing!");
+ if(!relaxed){
+ error("attr value delimiter missing!");
+ }
delimiter = ' ';
}
- else
- read();
-
+ else
+ read();
+
int p = txtPos;
pushText(delimiter, true);
@@ -701,14 +704,14 @@
nspCounts[depth] = nspCounts[depth - 1];
/*
- if(!relaxed){
+ 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();
@@ -733,9 +736,11 @@
int pos = txtPos;
while (true) {
- int c = read();
- if (c == ';')
- break;
+ int c = peek(0);
+ if (c == ';') {
+ read();
+ break;
+ }
if (c < 128
&& (c < '0' || c > '9')
&& (c < 'a' || c > 'z')
@@ -743,16 +748,21 @@
&& c != '_'
&& c != '-'
&& c != '#') {
- if(!relaxed){
- error("unterminated entity ref");
- }
+ if(!relaxed){
+ error("unterminated entity ref");
+ }
+
+ // BEGIN android-removed: avoid log spam.
+ // System.out.println("broken entitiy: "+get(pos-1));
+ // END android-removed
+
//; ends with:"+(char)c);
- if (c != -1)
- push(c);
+// if (c != -1)
+// push(c);
return;
}
- push(c);
+ push(read());
}
String code = get(pos);
@@ -843,10 +853,10 @@
result = peek[0];
peek[0] = peek[1];
}
- // else {
- // result = peek[0];
- // System.arraycopy (peek, 1, peek, 0, peekCount-1);
- // }
+ // else {
+ // result = peek[0];
+ // System.arraycopy (peek, 1, peek, 0, peekCount-1);
+ // }
peekCount--;
column++;
@@ -1121,8 +1131,8 @@
return version;
if (isProp(property, true, "xmldecl-standalone"))
return standalone;
- if (isProp(property, true, "location"))
- return location != null ? location : reader.toString();
+ if (isProp(property, true, "location"))
+ return location != null ? location : reader.toString();
return null;
}
@@ -1202,15 +1212,15 @@
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());
- }
+ 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();
}
@@ -1330,7 +1340,7 @@
nextImpl();
if (type < minType)
minType = type;
- // if (curr <= TEXT) type = curr;
+ // if (curr <= TEXT) type = curr;
}
while (minType > ENTITY_REF // ignorable
|| (minType >= TEXT && peekType() >= TEXT));
@@ -1411,9 +1421,9 @@
public void setProperty(String property, Object value)
throws XmlPullParserException {
if(isProp(property, true, "location"))
- location = value;
+ location = value;
else
- throw new XmlPullParserException("unsupported property: " + property);
+ throw new XmlPullParserException("unsupported property: " + property);
}
/**
@@ -1422,7 +1432,7 @@
* parser will be positioned on corresponding END_TAG.
*/
- // Implementation copied from Alek's mail...
+ // Implementation copied from Alek's mail...
public void skipSubTree() throws XmlPullParserException, IOException {
require(START_TAG, null, null);
diff --git a/xml/src/main/java/org/kxml2/wap/WbxmlSerializer.java b/xml/src/main/java/org/kxml2/wap/WbxmlSerializer.java
index 8c1b598..a977386 100644
--- a/xml/src/main/java/org/kxml2/wap/WbxmlSerializer.java
+++ b/xml/src/main/java/org/kxml2/wap/WbxmlSerializer.java
@@ -30,15 +30,11 @@
// TODO: make some of the "direct" WBXML token writing methods public??
/**
- * A class for writing WBXML.
- *
+ * A class for writing WBXML. Does not support namespaces yet.
*/
-
-
-
public class WbxmlSerializer implements XmlSerializer {
-
+
Hashtable stringTable = new Hashtable();
OutputStream out;
@@ -61,7 +57,14 @@
private String encoding;
+ private boolean headerSent = false;
+ /**
+ * Write an attribute.
+ * Calls to attribute() MUST follow a call to startTag() immediately.
+ * If there is no prefix defined for the given namespace,
+ * a prefix will be defined automatically.
+ */
public XmlSerializer attribute(String namespace, String name, String value) {
attributes.addElement(name);
attributes.addElement(value);
@@ -73,45 +76,71 @@
text (cdsect);
}
-
-
- /* silently ignore comment */
-
+ /**
+ * Add comment. Ignore for WBXML.
+ */
public void comment (String comment) {
+ // silently ignore comment
}
-
+ /**
+ * Docdecl isn't supported for WBXML.
+ */
public void docdecl (String docdecl) {
throw new RuntimeException ("Cannot write docdecl for WBXML");
}
-
+ /**
+ * EntityReference not supported for WBXML.
+ */
public void entityRef (String er) {
throw new RuntimeException ("EntityReference not supported for WBXML");
}
+ /**
+ * Return current tag depth.
+ */
public int getDepth() {
return depth;
}
-
+ /**
+ * Return the current value of the feature with given name.
+ */
public boolean getFeature (String name) {
return false;
}
+ /**
+ * Returns the namespace URI of the current element as set by startTag().
+ * Namespaces is not yet implemented.
+ */
public String getNamespace() {
- throw new RuntimeException("NYI");
+ // Namespaces is not yet implemented. So only null can be setted
+ return null;
}
+ /**
+ * Returns the name of the current element as set by startTag().
+ * It can only be null before first call to startTag() or when last endTag()
+ * is called to close first startTag().
+ */
public String getName() {
- throw new RuntimeException("NYI");
+ return pending;
}
+ /**
+ * Prefix for namespace not supported for WBXML. Not yet implemented.
+ */
public String getPrefix(String nsp, boolean create) {
throw new RuntimeException ("NYI");
}
-
+ /**
+ * Look up the value of a property.
+ * @param name The name of property. Name is any fully-qualified URI.
+ * @return The value of named property.
+ */
public Object getProperty (String name) {
return null;
}
@@ -119,31 +148,34 @@
public void ignorableWhitespace (String sp) {
}
-
+ /**
+ * Finish writing.
+ * All unclosed start tags will be closed and output will be flushed.
+ * After calling this method no more output can be serialized until
+ * next call to setOutput().
+ */
public void endDocument() throws IOException {
- writeInt(out, stringTableBuf.size());
+ flush();
+ }
- // write StringTable
+ /**
+ * Write all pending output to the stream.
+ * After first call string table willn't be used and you can't add tag
+ * which is not in tag table.
+ */
+ public void flush() throws IOException {
+ checkPending(false);
- out.write(stringTableBuf.toByteArray());
-
- // write buf
+ if (!headerSent) {
+ writeInt(out, stringTableBuf.size());
+ out.write(stringTableBuf.toByteArray());
+ headerSent = true;
+ }
out.write(buf.toByteArray());
-
- // ready!
-
- out.flush();
+ buf.reset();
}
-
- /** ATTENTION: flush cannot work since Wbxml documents require
- buffering. Thus, this call does nothing. */
-
- public void flush() {
- }
-
-
public void checkPending(boolean degenerated) throws IOException {
if (pending == null)
return;
@@ -154,27 +186,20 @@
// 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));
+ buf.write(len == 0
+ ? (degenerated ? Wbxml.LITERAL : Wbxml.LITERAL_C)
+ : (degenerated ? Wbxml.LITERAL_A : Wbxml.LITERAL_AC));
writeStrT(pending, false);
- }
- else {
+ } else {
if(idx[0] != tagPage){
tagPage=idx[0];
- buf.write(Wbxml.SWITCH_PAGE);
+ buf.write(Wbxml.SWITCH_PAGE);
buf.write(tagPage);
}
-
- buf.write(
- len == 0
- ? (degenerated ? idx[1] : idx[1] | 64)
- : (degenerated
- ? idx[1] | 128
- : idx[1] | 192));
-
+ buf.write(len == 0
+ ? (degenerated ? idx[1] : idx[1] | 64)
+ : (degenerated ? idx[1] | 128 : idx[1] | 192));
}
for (int i = 0; i < len;) {
@@ -186,7 +211,7 @@
}
else {
if(idx[0] != attrPage){
- attrPage = idx[0];
+ attrPage = idx[0];
buf.write(0);
buf.write(attrPage);
}
@@ -198,9 +223,9 @@
}
else {
if(idx[0] != attrPage){
- attrPage = idx[0];
+ attrPage = idx[0];
buf.write(0);
- buf.write(attrPage);
+ buf.write(attrPage);
}
buf.write(idx[1]);
}
@@ -214,60 +239,79 @@
attributes.removeAllElements();
}
-
+ /**
+ * Not Yet Implemented.
+ */
public void processingInstruction(String pi) {
throw new RuntimeException ("PI NYI");
}
-
+ /**
+ * Set feature identified by name. There are no supported functions.
+ */
public void setFeature(String name, boolean value) {
throw new IllegalArgumentException ("unknown feature "+name);
}
-
-
+ /**
+ * Set the output to the given writer. Wbxml requires an OutputStream.
+ */
public void setOutput (Writer writer) {
throw new RuntimeException ("Wbxml requires an OutputStream!");
}
+ /**
+ * Set to use binary output stream with given encoding.
+ */
public void setOutput (OutputStream out, String encoding) throws IOException {
- this.encoding = encoding == null ? "UTF-8" : encoding;
+ this.encoding = encoding == null ? "UTF-8" : encoding;
this.out = out;
buf = new ByteArrayOutputStream();
stringTableBuf = new ByteArrayOutputStream();
+ headerSent = false;
// ok, write header
}
-
+ /**
+ * Binds the given prefix to the given namespace. Not yet implemented.
+ */
public void setPrefix(String prefix, String nsp) {
throw new RuntimeException("NYI");
}
+ /**
+ * Set the value of a property. There are no supported properties.
+ */
public void setProperty(String property, Object value) {
throw new IllegalArgumentException ("unknown property "+property);
}
-
- public void startDocument(String s, Boolean b) throws IOException{
+ /**
+ * Write version and encoding information.
+ * This method can only be called just after setOutput.
+ * @param encoding Document encoding. Default is UTF-8.
+ * @param standalone Not used in WBXML.
+ */
+ public void startDocument(String encoding, Boolean standalone) 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
- if(s != null){
- encoding = s;
+ if(encoding != null){
+ this.encoding = encoding;
}
- if (encoding.toUpperCase().equals("UTF-8")){
+ if (this.encoding.toUpperCase().equals("UTF-8")){
out.write(106);
- }else if (encoding.toUpperCase().equals("ISO-8859-1")){
+ }else if (this.encoding.toUpperCase().equals("ISO-8859-1")){
out.write(0x04);
}else{
- throw new UnsupportedEncodingException(s);
+ throw new UnsupportedEncodingException(encoding);
}
}
@@ -287,121 +331,114 @@
}
public XmlSerializer text(char[] chars, int start, int len) throws IOException {
-
- checkPending(false);
-
+ checkPending(false);
writeStr(new String(chars, start, len));
-
return this;
}
public XmlSerializer text(String text) throws IOException {
-
checkPending(false);
-
writeStr(text);
-
return this;
}
-
- /** Used in text() and attribute() to write text */
-
+ /**
+ * Used in text() and attribute() to write text.
+ */
private void writeStr(String text) throws IOException{
int p0 = 0;
- int lastCut = 0;
- int len = text.length();
-
- while(p0 < len){
- while(p0 < len && text.charAt(p0) < 'A' ){ // skip interpunctation
- p0++;
- }
- int p1 = p0;
- while(p1 < len && text.charAt(p1) >= 'A'){
- p1++;
- }
-
- if(p1 - p0 > 10) {
-
- if(p0 > lastCut && text.charAt(p0-1) == ' '
- && stringTable.get(text.substring(p0, p1)) == null){
-
- buf.write(Wbxml.STR_T);
- writeStrT(text.substring(lastCut, p1), false);
- }
- else {
-
- if(p0 > lastCut && text.charAt(p0-1) == ' '){
- p0--;
- }
-
- if(p0 > lastCut){
- buf.write(Wbxml.STR_T);
- writeStrT(text.substring(lastCut, p0), false);
- }
- buf.write(Wbxml.STR_T);
- writeStrT(text.substring(p0, p1), true);
- }
- lastCut = p1;
- }
- p0 = p1;
+ int lastCut = 0;
+ int len = text.length();
+
+ if (headerSent) {
+ writeStrI(buf, text);
+ return;
}
+
+ while(p0 < len){
+ while(p0 < len && text.charAt(p0) < 'A' ){ // skip interpunctation
+ p0++;
+ }
+ int p1 = p0;
+ while (p1 < len && text.charAt(p1) >= 'A'){
+ p1++;
+ }
+
+ if (p1 - p0 > 10) {
+ if (p0 > lastCut && text.charAt(p0-1) == ' '
+ && stringTable.get(text.substring(p0, p1)) == null){
+ buf.write(Wbxml.STR_T);
+ writeStrT(text.substring(lastCut, p1), false);
+ }
+ else {
+ if(p0 > lastCut && text.charAt(p0-1) == ' '){
+ p0--;
+ }
- if(lastCut < len){
- buf.write(Wbxml.STR_T);
- writeStrT(text.substring(lastCut, len), false);
- }
+ if(p0 > lastCut){
+ buf.write(Wbxml.STR_T);
+ writeStrT(text.substring(lastCut, p0), false);
+ }
+ buf.write(Wbxml.STR_T);
+ writeStrT(text.substring(p0, p1), true);
+ }
+ lastCut = p1;
+ }
+ p0 = p1;
+ }
+
+ if(lastCut < len){
+ buf.write(Wbxml.STR_T);
+ writeStrT(text.substring(lastCut, len), false);
+ }
}
public XmlSerializer endTag(String namespace, String name) throws IOException {
-
// current = current.prev;
-
- if (pending != null)
+ if (pending != null) {
checkPending(true);
- else
+ } else {
buf.write(Wbxml.END);
-
+ }
depth--;
-
return this;
}
/**
- * @throws IOException */
-
+ * @throws IOException
+ */
public void writeWapExtension(int type, Object data) throws IOException {
checkPending(false);
- buf.write(type);
- switch(type){
- case Wbxml.EXT_0:
- case Wbxml.EXT_1:
- case Wbxml.EXT_2:
- break;
-
- case Wbxml.OPAQUE:
- byte[] bytes = (byte[]) data;
- writeInt(buf, bytes.length);
- buf.write(bytes);
- break;
-
- case Wbxml.EXT_I_0:
- case Wbxml.EXT_I_1:
- case Wbxml.EXT_I_2:
- writeStrI(buf, (String) data);
- break;
+ buf.write(type);
+ switch(type){
+ case Wbxml.EXT_0:
+ case Wbxml.EXT_1:
+ case Wbxml.EXT_2:
+ break;
+
+ case Wbxml.OPAQUE:
+ byte[] bytes = (byte[]) data;
+ writeInt(buf, bytes.length);
+ buf.write(bytes);
+ break;
+
+ case Wbxml.EXT_I_0:
+ case Wbxml.EXT_I_1:
+ case Wbxml.EXT_I_2:
+ writeStrI(buf, (String) data);
+ break;
- case Wbxml.EXT_T_0:
- case Wbxml.EXT_T_1:
- case Wbxml.EXT_T_2:
- writeStrT((String) data, false);
- break;
-
- default:
- throw new IllegalArgumentException();
- }
+ case Wbxml.EXT_T_0:
+ case Wbxml.EXT_T_1:
+ case Wbxml.EXT_T_2:
+ writeStrT((String) data, false);
+ break;
+
+ default:
+ throw new IllegalArgumentException();
+ }
}
// ------------- internal methods --------------------------
@@ -423,49 +460,58 @@
}
void writeStrI(OutputStream out, String s) throws IOException {
- byte[] data = s.getBytes(encoding);
- out.write(data);
+ byte[] data = s.getBytes(encoding);
+ out.write(data);
out.write(0);
}
private final void writeStrT(String s, boolean mayPrependSpace) throws IOException {
- Integer idx = (Integer) stringTable.get(s);
-
- if (idx != null) {
- writeInt(buf, idx.intValue());
+ Integer idx = (Integer) stringTable.get(s);
+ writeInt(buf, idx == null
+ ? addToStringTable(s, mayPrependSpace)
+ : idx.intValue());
+ }
+
+
+ /**
+ * Add string to string table. Not permitted after string table has been flushed.
+ *
+ * @param s string to be added to the string table
+ * @param mayPrependSpace is set, a space is prepended to the string to archieve better compression results
+ * @return offset of s in the string table
+ */
+ public int addToStringTable(String s, boolean mayPrependSpace) throws IOException {
+ if (headerSent) {
+ throw new IOException("stringtable sent");
}
- else{
- int i = stringTableBuf.size();
- if(s.charAt(0) >= '0' && mayPrependSpace){
- s = ' ' + s;
- writeInt(buf, i+1);
- }
- else{
- writeInt(buf, i);
- }
-
- stringTable.put(s, new Integer(i));
- if(s.charAt(0) == ' '){
- stringTable.put(s.substring(1), new Integer(i+1));
- }
- int j = s.lastIndexOf(' ');
- if(j > 1){
- stringTable.put(s.substring(j), new Integer(i+j));
- stringTable.put(s.substring(j+1), new Integer(i+j+1));
- }
+
+ int i = stringTableBuf.size();
+ int offset = i;
+ if(s.charAt(0) >= '0' && mayPrependSpace){
+ s = ' ' + s;
+ offset++;
+ }
+
+ stringTable.put(s, new Integer(i));
+ if(s.charAt(0) == ' '){
+ stringTable.put(s.substring(1), new Integer(i+1));
+ }
+ int j = s.lastIndexOf(' ');
+ if(j > 1){
+ stringTable.put(s.substring(j), new Integer(i+j));
+ stringTable.put(s.substring(j+1), new Integer(i+j+1));
+ }
- writeStrI(stringTableBuf, s);
- stringTableBuf.flush();
- }
-
+ writeStrI(stringTableBuf, s);
+ stringTableBuf.flush();
+ return offset;
}
/**
* 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) {
// TODO: clear entries in tagTable?
@@ -499,6 +545,7 @@
* 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.
+ * Must be called BEFORE use attribute(), flush() etc.
*/
public void setAttrValueTable(int page, String[] attrValueTable) {
// clear entries in this.table!