From: hansonr Date: Wed, 20 Jun 2018 10:40:46 +0000 (+0100) Subject: update of javajs package; adds org.apache.harmony, org.xml.sax.helpers X-Git-Tag: Release_2_11_4_0~45^2~18^2~683 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=5e556aaaedbcf56063c72677364c7fe2b961230d;p=jalview.git update of javajs package; adds org.apache.harmony, org.xml.sax.helpers File format identified as Fasta --- diff --git a/src/jalview/bin/Jalview.java b/src/jalview/bin/Jalview.java index 30620a1..2007814 100755 --- a/src/jalview/bin/Jalview.java +++ b/src/jalview/bin/Jalview.java @@ -77,6 +77,9 @@ import groovy.util.GroovyScriptEngine; */ public class Jalview { + + // BH 6/19/2018 starting to work on JS version - just discovering issues + /* * singleton instance of this class */ @@ -86,8 +89,14 @@ public class Jalview public static AlignFrame currentAlignFrame; + public static boolean isJS = /** @j2sNative true || */ // BH 2018 + false; + static { + + if (!isJS) + { // BH 2018 // grab all the rights we can the JVM Policy.setPolicy(new Policy() { @@ -104,6 +113,8 @@ public class Jalview { } }); + + } } /** @@ -188,7 +199,12 @@ public class Jalview */ void doMain(String[] args) { - System.setSecurityManager(null); + + if (!isJS) + { + System.setSecurityManager(null); + } + System.out .println("Java version: " + System.getProperty("java.version")); System.out.println(System.getProperty("os.arch") + " " diff --git a/src/javajs/api/GenericZipTools.java b/src/javajs/api/GenericZipTools.java index a0b0993..47a2da2 100644 --- a/src/javajs/api/GenericZipTools.java +++ b/src/javajs/api/GenericZipTools.java @@ -15,6 +15,8 @@ public interface GenericZipTools { public InputStream newGZIPInputStream(InputStream bis) throws IOException; + public InputStream newBZip2InputStream(InputStream bis) throws IOException; + public Object getZipFileDirectory(BufferedInputStream bis, String[] subFileList, int listPtr, boolean asBufferedInputStream); diff --git a/src/javajs/api/JSInterface.java b/src/javajs/api/JSInterface.java index d824543..0f785fa 100644 --- a/src/javajs/api/JSInterface.java +++ b/src/javajs/api/JSInterface.java @@ -19,6 +19,7 @@ public interface JSInterface { void setScreenDimension(int width, int height); boolean setStatusDragDropped(int mode, int x, int y, String fileName); void startHoverWatcher(boolean enable); + void update(); // these are not general methods //Object getGLmolView(); diff --git a/src/javajs/api/js/J2SObjectInterface.java b/src/javajs/api/js/J2SObjectInterface.java index fbe126d..687f642 100644 --- a/src/javajs/api/js/J2SObjectInterface.java +++ b/src/javajs/api/js/J2SObjectInterface.java @@ -1,7 +1,7 @@ package javajs.api.js; /** - * methods in JSmol JavaScript accessed in Jmol (aka J2S) + * methods in JSmol JavaScript accessed in Jmol */ public interface J2SObjectInterface { diff --git a/src/javajs/util/A4.java b/src/javajs/util/A4.java index df173a6..d20b6c2 100644 --- a/src/javajs/util/A4.java +++ b/src/javajs/util/A4.java @@ -34,8 +34,7 @@ import javajs.util.T3; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 * for unique constructor and method names - * for the optimization of compiled JavaScript using Java2Script. - * + * for the optimization of compiled JavaScript using Java2Script */ public class A4 implements JSONEncodable, Serializable { @@ -44,11 +43,6 @@ public class A4 implements JSONEncodable, Serializable { */ /** - * - */ - private static final long serialVersionUID = 1L; - -/** * The x coordinate. */ public float x; diff --git a/src/javajs/util/AU.java b/src/javajs/util/AU.java index cd4ed03..f873116 100644 --- a/src/javajs/util/AU.java +++ b/src/javajs/util/AU.java @@ -139,7 +139,7 @@ final public class AU { /** * @j2sNative * - * if (Clazz.newArray$ && newLength < oldLength) return Clazz.newArray$(-1, array, 0, newLength); + * if (newLength < oldLength) return Clazz.array(-1, array, 0, newLength); */ {} Object t = newInstanceO(array, newLength); @@ -181,7 +181,7 @@ final public class AU { /** * @j2sNative * - * if (Clazz.newArray$ && newLength < oldLength) return Clazz.newArray$(-1, array, 0, newLength); + * if (newLength < oldLength) return Clazz.array(-1, array, 0, newLength); */ {} String[] t = new String[newLength]; @@ -220,7 +220,7 @@ final public class AU { /** * @j2sNative * - * if (Clazz.newArray$ && newLength < oldLength) return Clazz.newArray$(-1, array, 0, newLength); + * if (newLength < oldLength) return Clazz.array(-1, array, 0, newLength); */ {} float[] t = new float[newLength]; @@ -237,7 +237,7 @@ final public class AU { /** * @j2sNative * - * if (Clazz.newArray$ && newLength < oldLength) return Clazz.newArray$(-1, array, 0, newLength); + * if (newLength < oldLength) return Clazz.array(-1, array, 0, newLength); */ {} int[] t = new int[newLength]; @@ -265,7 +265,7 @@ final public class AU { /** * @j2sNative * - * if (Clazz.newArray$) return Clazz.newArray$(-1, array, i0, n); + * return Clazz.array(-1, array, i0, n); * */ { @@ -282,7 +282,7 @@ final public class AU { /** * @j2sNative * - * if (Clazz.newArray$) return Clazz.newArray$(-1, array, i0, n).reverse(); + * return Clazz.array(-1, array, i0, n).reverse(); */ { } @@ -300,7 +300,7 @@ final public class AU { /** * @j2sNative * - * if (Clazz.newArray$ && newLength < oldLength) return Clazz.newArray$(-1, array, 0, newLength); + * if (newLength < oldLength) return Clazz.array(-1, array, 0, newLength); */ {} short[] t = new short[newLength]; @@ -317,7 +317,7 @@ final public class AU { /** * @j2sNative * - * if (Clazz.newArray$ && newLength < oldLength) return Clazz.newArray$(-1, array, 0, newLength); + * if (newLength < oldLength) return Clazz.array(-1, array, 0, newLength); */ {} byte[] t = new byte[newLength]; @@ -334,7 +334,7 @@ final public class AU { /** * @j2sNative * - * if (Clazz.newArray$ && newLength < oldLength) return Clazz.newArray$(-1, array, 0, newLength); + * if (newLength < oldLength) return Clazz.array(-1, array, 0, newLength); */ {} boolean[] t = new boolean[newLength]; diff --git a/src/javajs/util/AjaxURLConnection.java b/src/javajs/util/AjaxURLConnection.java index cef98c8..0b038c3 100644 --- a/src/javajs/util/AjaxURLConnection.java +++ b/src/javajs/util/AjaxURLConnection.java @@ -6,7 +6,6 @@ import java.io.InputStream; import java.net.URL; import java.net.URLConnection; -import javajs.api.ResettableStream; import javajs.api.js.J2SObjectInterface; /** @@ -35,6 +34,9 @@ public class AjaxURLConnection extends URLConnection { * the method is "private", but in JavaScript that can still be overloaded. * Just set something to org.jmol.awtjs.JmolURLConnection.prototype.doAjax * + * + * @param isBinary + * * @return file data as a javajs.util.SB or byte[] depending upon the file * type. * @@ -42,16 +44,16 @@ public class AjaxURLConnection extends URLConnection { */ @SuppressWarnings("null") private Object doAjax(boolean isBinary) { - J2SObjectInterface jmol = null; + J2SObjectInterface j2s = null; /** * @j2sNative * - * jmol = J2S || Jmol; + * j2s = J2S; * */ { } - return jmol._doAjax(url, postOut, bytesOut, isBinary); + return j2s._doAjax(url, postOut, bytesOut, isBinary); } @Override @@ -71,48 +73,44 @@ public class AjaxURLConnection extends URLConnection { @Override public InputStream getInputStream() { - BufferedInputStream bis = getAttachedStreamData(url); - if (bis != null) - return bis; - Object o = doAjax(true); - return ( - AU.isAB(o) ? Rdr.getBIS((byte[]) o) - : o instanceof SB ? Rdr.getBIS(Rdr.getBytesFromSB((SB) o)) - : o instanceof String ? Rdr.getBIS(((String) o).getBytes()) - : bis - ); + BufferedInputStream is = getAttachedStreamData(url, false); + return (is == null ? attachStreamData(url, doAjax(true)) : is); } - @SuppressWarnings("unused") + /** - * J2S will attach a BufferedInputStream to any URL that is + * J2S will attach the data (String, SB, or byte[]) to any URL that is * retrieved using a ClassLoader. This improves performance by * not going back to the server every time a second time, since * the first time in Java is usually just to see if it exists. * - * This stream can be re-used, but it has to be reset. Java for some - * reason does not allow a BufferedInputStream to fully reset its - * inner streams. We enable that by force-casting the stream as a - * javax.io stream and then applying resetStream() to that. - * - * * @param url - * @return + * @return String, SB, or byte[] */ - public static BufferedInputStream getAttachedStreamData(URL url) { - BufferedInputStream bis = null; + public static BufferedInputStream getAttachedStreamData(URL url, boolean andDelete) { + + Object data = null; /** * @j2sNative * - * bis = url._streamData; + * data = url._streamData; + * if (andDelete) url._streamData = null; */ { } - if (bis != null) - ((ResettableStream) (Object) bis).resetStream(); - return bis; + return (data == null ? null : Rdr.toBIS(data)); } - /** + public static BufferedInputStream attachStreamData(URL url, Object o) { + /** + * @j2sNative + * + * url._streamData = o; + */ + + return (o == null ? null : Rdr.toBIS(o)); + } + + /** * @return javajs.util.SB or byte[], depending upon the file type */ public Object getContents() { diff --git a/src/javajs/util/BC.java b/src/javajs/util/BC.java index df9c9f9..5722efd 100644 --- a/src/javajs/util/BC.java +++ b/src/javajs/util/BC.java @@ -66,7 +66,7 @@ public class BC { * if (o.fracIEEE == null) * o.setFracIEEE(); * var m = ((x & 0x7F800000) >> 23); - * return ((x & 0x80000000) == 0 ? 1 : -1) * o.shiftIEEE((x & 0x7FFFFF) | 0x800000, m - 149); + * return ((x & 0x80000000) == 0 ? 1 : -1) * o.shiftIEEE$D$I((x & 0x7FFFFF) | 0x800000, m - 149); * */ { @@ -96,7 +96,6 @@ public class BC { /** * @j2sNative - * var o = javajs.util.BC; * var b1, b2, b3, b4, b5; * * if (isBigEndian) { @@ -115,8 +114,8 @@ public class BC { * var s = ((b1 & 0x80) == 0 ? 1 : -1); * var e = (((b1 & 0x7F) << 4) | (b2 >> 4)) - 1026; * b2 = (b2 & 0xF) | 0x10; - * return s * (o.shiftIEEE(b2, e) + o.shiftIEEE(b3, e - 8) + o.shiftIEEE(b4, e - 16) - * + o.shiftIEEE(b5, e - 24)); + * return s * (C$.shiftIEEE$D$I(b2, e) +C$.shiftIEEE$D$I(b3, e - 8) + C$.shiftIEEE$D$I(b4, e - 16) + * + C$.shiftIEEE$D$I(b5, e - 24)); */ { double d; diff --git a/src/javajs/util/BS.java b/src/javajs/util/BS.java index 0bfa5a6..1f3aaa4 100644 --- a/src/javajs/util/BS.java +++ b/src/javajs/util/BS.java @@ -79,7 +79,7 @@ import javajs.api.JSONEncodable; */ public class BS implements Cloneable, JSONEncodable { /* - * BitSets are packed into arrays of "wrangeords." + * BitSets are packed into arrays of "words." * * An int, which consists of 32 bits, requiring 5 address bits, is used for * the JavaScript port. @@ -736,7 +736,7 @@ public class BS implements Cloneable, JSONEncodable { * @j2sNative * if (n == this.words.length) return; * if (n == this.wordsInUse) { - * this.words = Clazz.newArray$(-1, this.words, 0, n); + * this.words = Clazz.array(-1, this.words, 0, n); * return; * } */ @@ -818,7 +818,7 @@ public class BS implements Cloneable, JSONEncodable { * * @j2sNative * - * bs.words = Clazz.newArray(-1, bitsetToCopy.words, 0, bs.wordsInUse = wordCount); + * bs.words = Clazz.array(-1, bitsetToCopy.words, 0, bs.wordsInUse = wordCount); * */ { @@ -907,11 +907,11 @@ public class BS implements Cloneable, JSONEncodable { return null; len -= 2; for (int i = len; --i >= 2;) - if (!PT.isDigit(ch = str.charAt(i)) && ch != ' ' && ch != '\t' + if (((ch = str.charAt(i)) < 48 || ch > 57) && ch != ' ' && ch != '\t' && ch != ':') return null; int lastN = len; - while (PT.isDigit(str.charAt(--lastN))) { + while (48 <= (ch = str.charAt(--lastN)) && ch <= 57) { // loop } if (++lastN == len) @@ -947,7 +947,7 @@ public class BS implements Cloneable, JSONEncodable { iThis = -2; break; default: - if (PT.isDigit(ch)) { + if (48 <= ch && ch <= 57) { if (iThis < 0) iThis = 0; iThis = (iThis * 10) + (ch - 48); diff --git a/src/javajs/util/BinaryDocument.java b/src/javajs/util/BinaryDocument.java index 7ac5a56..73ec57b 100644 --- a/src/javajs/util/BinaryDocument.java +++ b/src/javajs/util/BinaryDocument.java @@ -262,6 +262,7 @@ public class BinaryDocument extends BC implements GenericBinaryDocument { return intToFloat(readInt()); } + @SuppressWarnings("unused") @Override public double readDouble() throws IOException { /** @@ -270,14 +271,17 @@ public class BinaryDocument extends BC implements GenericBinaryDocument { * * @j2sNative * - * this.readByteArray(this.t8, 0, 8); - * return this.bytesToDoubleToFloat(this.t8, 0, this.isBigEndian); - * + * */ { nBytes += 8; - return (isBigEndian ? ioReadDouble() : Double.longBitsToDouble(readLELong())); + if (true) + return (isBigEndian ? ioReadDouble() + : Double.longBitsToDouble(readLELong())); } + // this is the JavaScript-only part + this.readByteArray(this.t8, 0, 8); + return bytesToDoubleToFloat(this.t8, 0, this.isBigEndian); } private double ioReadDouble() throws IOException { diff --git a/src/javajs/util/CifDataParser.java b/src/javajs/util/CifDataParser.java index 5be12fd..51e969c 100644 --- a/src/javajs/util/CifDataParser.java +++ b/src/javajs/util/CifDataParser.java @@ -658,10 +658,10 @@ public class CifDataParser implements GenericCifDataParser { public String fixKey(String key) { // PRELIMINARY -- BilBao _magnetic // PRELIMINARY -- Jana2006 - return (PT.rep( + return ( key.startsWith("_magnetic") ? key.substring(9) : key.startsWith("_jana") ? key.substring(5) - : key, ".", "_").toLowerCase()); + : key).replace('.', '_').toLowerCase(); } //////////////////// private methods //////////////////// diff --git a/src/javajs/util/CompoundDocDirEntry.java b/src/javajs/util/CompoundDocDirEntry.java index e60b874..a57f6af 100644 --- a/src/javajs/util/CompoundDocDirEntry.java +++ b/src/javajs/util/CompoundDocDirEntry.java @@ -93,4 +93,9 @@ class CompoundDocDirEntry { //System.out.println(entryName + " type " + entryType); return true; } + + @Override + public String toString() { + return entryName + " " + lenStream; + } } \ No newline at end of file diff --git a/src/javajs/util/DF.java b/src/javajs/util/DF.java index 1d8a2f1..b5c8717 100644 --- a/src/javajs/util/DF.java +++ b/src/javajs/util/DF.java @@ -73,7 +73,7 @@ public class DF { if (decimalDigits > formattingStrings.length) decimalDigits = formattingStrings.length; if (value == 0) - return formattingStrings[decimalDigits] + "E+0"; + return formattingStrings[decimalDigits - 1] + "E+0"; //scientific notation n = 0; double d; @@ -87,9 +87,19 @@ public class DF { String s = ("" + d).toUpperCase(); int i = s.indexOf("E"); n = PT.parseInt(s.substring(i + 1)) + n; - return (i < 0 ? "" + value : formatDecimal(PT.parseFloat(s.substring( - 0, i)), decimalDigits - 1) - + "E" + (n >= 0 ? "+" : "") + n); + String sf; + if (i < 0) { + sf = "" + value; + } else { + float f = PT.parseFloat(s.substring(0, i)); + if (f == 10 || f == -10) { + //d = 9.99999997465; n = -6 --> 10.00000E-5 + f /= 10; + n += (n < 0 ? 1 : -1); + } + sf = formatDecimal(f, decimalDigits - 1); + } + return sf + "E" + (n >= 0 ? "+" : "") + n; } if (decimalDigits >= formattingStrings.length) diff --git a/src/javajs/util/JSJSONParser.java b/src/javajs/util/JSJSONParser.java index ce580e0..552270d 100644 --- a/src/javajs/util/JSJSONParser.java +++ b/src/javajs/util/JSJSONParser.java @@ -4,9 +4,6 @@ import java.util.HashMap; import java.util.Hashtable; import java.util.Map; -import javajs.J2SIgnoreImport; - - /** * a very simple JSON parser for JSON objects that are compatible with JavaScript @@ -23,7 +20,6 @@ import javajs.J2SIgnoreImport; * @author Bob Hanson * */ -@J2SIgnoreImport({ HashMap.class }) public class JSJSONParser { private String str; @@ -59,11 +55,13 @@ public class JSJSONParser { * Could return Integer, Float, Boolean, String, Map, Lst, or null * * @param str + * @param asHashTable * @return a object equivalent to the JSON string str * */ - public Object parse(String str) { + public Object parse(String str, boolean asHashTable) { index = 0; + this.asHashTable = asHashTable; this.str = str; len = str.length(); return getValue(false); @@ -143,7 +141,7 @@ public class JSJSONParser { if (isKey && c == 0) throw new JSONException("invalid key"); - String string = str.substring(i, index); + String string = str.substring(i, index).trim(); // check for the only valid simple words: true, false, null (lower case) // and in this case, only for @@ -160,7 +158,6 @@ public class JSJSONParser { } } // only numbers from here on: - c = string.charAt(0); if (c >= '0' && c <= '9' || c == '-') try { @@ -280,7 +277,7 @@ public class JSJSONParser { switch (getChar()) { case ']': return l; - case 0: + case '\0': throw new JSONException("invalid array"); } returnChar(); diff --git a/src/javajs/util/JSONException.java b/src/javajs/util/JSONException.java index 157f100..58af722 100644 --- a/src/javajs/util/JSONException.java +++ b/src/javajs/util/JSONException.java @@ -1,12 +1,7 @@ package javajs.util; public class JSONException extends RuntimeException { - /** - * - */ - private static final long serialVersionUID = 1L; - - public JSONException(String message) { + public JSONException(String message) { super(message); } diff --git a/src/javajs/util/JSThread.java b/src/javajs/util/JSThread.java index c2f3c4d..be94c00 100644 --- a/src/javajs/util/JSThread.java +++ b/src/javajs/util/JSThread.java @@ -200,7 +200,9 @@ public abstract class JSThread extends Thread implements JSFunction { * @j2sNative * * setTimeout( - * function() {java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent$java_awt_AWTEvent(Clazz.new(java.awt.event.InvocationEvent.c$$O$Runnable,[me, r]))}, + * function() { + * java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent$java_awt_AWTEvent( + * Clazz.new_(java.awt.event.InvocationEvent.c$$O$Runnable,[me, r]))}, * delay); * */ diff --git a/src/javajs/util/M3.java b/src/javajs/util/M3.java index 7749277..88f6f4e 100644 --- a/src/javajs/util/M3.java +++ b/src/javajs/util/M3.java @@ -27,15 +27,19 @@ import java.io.Serializable; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 for unique * constructor and method names for the optimization of compiled - * JavaScript using Java2Script. - * + * JavaScript using Java2Script * * */ -@SuppressWarnings("serial") public class M3 extends M34 implements Serializable { /** + * Constructs and initializes a Matrix3f to all zeros. + */ + public M3() { + } + + /** * Constructs and initializes a Matrix3f from the specified 9 element array. * this.m00 =v[0], this.m01=v[1], etc. * diff --git a/src/javajs/util/M34.java b/src/javajs/util/M34.java index b0882dd..260a82c 100644 --- a/src/javajs/util/M34.java +++ b/src/javajs/util/M34.java @@ -7,8 +7,7 @@ package javajs.util; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 for unique * constructor and method names for the optimization of compiled - * JavaScript using Java2Script. - * and for subclassing to M3 and M4 + * JavaScript using Java2Script and for subclassing to M3 and M4 * */ public abstract class M34 { diff --git a/src/javajs/util/M4.java b/src/javajs/util/M4.java index 1f16335..58bd355 100644 --- a/src/javajs/util/M4.java +++ b/src/javajs/util/M4.java @@ -23,8 +23,7 @@ package javajs.util; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 for unique * constructor and method names for the optimization of compiled - * JavaScript using Java2Script. - * + * JavaScript using Java2Script */ public class M4 extends M34 { @@ -63,6 +62,9 @@ public class M4 extends M34 { */ public float m33 = 0; + /** + * all zeros + */ public M4() { } /** diff --git a/src/javajs/util/Measure.java b/src/javajs/util/Measure.java index 8fd799b..8b21cfe 100644 --- a/src/javajs/util/Measure.java +++ b/src/javajs/util/Measure.java @@ -235,7 +235,6 @@ final public class Measure { } /** - * if vAC is dispensible vNorm can be vAC * @param pointA * @param pointB * @param pointC diff --git a/src/javajs/util/MessagePackReader.java b/src/javajs/util/MessagePackReader.java index e9cdb7b..a0e6b8b 100644 --- a/src/javajs/util/MessagePackReader.java +++ b/src/javajs/util/MessagePackReader.java @@ -1,5 +1,7 @@ package javajs.util; +import java.io.BufferedInputStream; +import java.io.InputStream; import java.util.Hashtable; import java.util.Map; @@ -91,6 +93,17 @@ public class MessagePackReader { doc = binaryDoc; } + public MessagePackReader() { + // for reflection + } + + public Map getMapForStream(BufferedInputStream is) throws Exception { + doc = new BinaryDocument().setStream(is, true); + Map map = readMap(); + is.close(); + return map; + } + @SuppressWarnings("unchecked") public Map readMap() throws Exception { return (Map) getNext(null, 0); diff --git a/src/javajs/util/OC.java b/src/javajs/util/OC.java index 81cda57..98151d1 100644 --- a/src/javajs/util/OC.java +++ b/src/javajs/util/OC.java @@ -6,7 +6,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import javajs.J2SIgnoreImport; import javajs.api.BytePoster; import javajs.api.GenericOutputChannel; import javajs.api.js.J2SObjectInterface; @@ -44,7 +43,6 @@ import javajs.api.js.J2SObjectInterface; * */ -@J2SIgnoreImport({ java.io.FileOutputStream.class }) public class OC extends OutputStream implements GenericOutputChannel { private BytePoster bytePoster; // only necessary for writing to http:// or https:// @@ -84,7 +82,7 @@ public class OC extends OutputStream implements GenericOutputChannel { this.fileName = fileName; this.os = os; isLocalFile = (fileName != null && !isRemote(fileName)); - if (asWriter && !isBase64 && os != null) + if (asWriter && !isBase64 && os != null) bw = Rdr.getBufferedWriter(os, null); return this; } diff --git a/src/javajs/util/P3.java b/src/javajs/util/P3.java index edfebfe..1e1dfdb 100644 --- a/src/javajs/util/P3.java +++ b/src/javajs/util/P3.java @@ -28,12 +28,15 @@ package javajs.util; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 * for unique constructor and method names - * for the optimization of compiled JavaScript using Java2Script. - * + * for the optimization of compiled JavaScript using Java2Script * */ public class P3 extends T3 { + public P3() { + // ignore T3 + } + public static P3 newP(T3 t) { P3 p = new P3(); p.x = t.x; diff --git a/src/javajs/util/P3i.java b/src/javajs/util/P3i.java index 381aede..8f39550 100644 --- a/src/javajs/util/P3i.java +++ b/src/javajs/util/P3i.java @@ -29,8 +29,7 @@ package javajs.util; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 for unique * constructor and method names for the optimization of compiled - * JavaScript using Java2Script. - * + * JavaScript using Java2Script */ public class P3i extends T3i { diff --git a/src/javajs/util/P4.java b/src/javajs/util/P4.java index 2145696..6478602 100644 --- a/src/javajs/util/P4.java +++ b/src/javajs/util/P4.java @@ -28,11 +28,14 @@ package javajs.util; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 * for unique constructor and method names - * for the optimization of compiled JavaScript using Java2Script. - * + * for the optimization of compiled JavaScript using Java2Script */ public class P4 extends T4 { + public P4() { + // skip T4() constructor + } + public static P4 new4(float x, float y, float z, float w) { P4 pt = new P4(); pt.set4(x, y, z, w); diff --git a/src/javajs/util/PT.java b/src/javajs/util/PT.java index c544967..81653cf 100644 --- a/src/javajs/util/PT.java +++ b/src/javajs/util/PT.java @@ -31,7 +31,6 @@ import java.lang.reflect.Array; import java.util.Map; import java.util.Map.Entry; -import javajs.J2SIgnoreImport; import javajs.api.JSONEncodable; /** @@ -41,7 +40,6 @@ import javajs.api.JSONEncodable; * */ -@J2SIgnoreImport(value = { java.lang.reflect.Array.class }) public class PT { public static int parseInt(String str) { @@ -427,33 +425,34 @@ public class PT { return (ichLast < ich ? "" : str.substring(ich, ichLast + 1)); } - public static double dVal(String s) throws NumberFormatException { - /** - * @j2sNative - * - * if(s==null) - * throw new NumberFormatException("null"); - * var d=parseFloat(s); - * if(isNaN(d)) - * throw new NumberFormatException("Not a Number : "+s); - * return d - * - */ - { - return Double.valueOf(s).doubleValue(); - } - } - - public static float fVal(String s) throws NumberFormatException { - /** - * @j2sNative - * - * return this.dVal(s); - */ - { - return Float.parseFloat(s); - } - } +// public static double dVal(String s) throws NumberFormatException { +// /** +// * @j2sNative +// * +// * if(s==null) +// * throw new NumberFormatException("null"); +// * var d=parseFloat(s); +// * if(isNaN(d)) +// * throw new NumberFormatException("Not a Number : "+s); +// * return d +// * +// */ +// { +// return Double.valueOf(s).doubleValue(); +// } +// } +// +// public static float fVal(String s) throws NumberFormatException { +// /** +// * @j2sNative +// * +// * return this.dVal(s); +// */ +// { +// +// return Float.parseFloat(s); +// } +// } public static int parseIntRange(String str, int ichMax, int[] next) { int cch = str.length(); @@ -567,6 +566,34 @@ public class PT { } /** + * single- or double-quoted string or up to the first space -- like HTML5 + * not case-sensitive + * + * @param line + * @param key + * @return attribute + */ + public static String getQuotedOrUnquotedAttribute(String line, String key) { + if (line == null || key == null) + return null; + int pt = line.toLowerCase().indexOf(key.toLowerCase() + "="); + if (pt < 0 || (pt = pt + key.length() + 1) >= line.length()) + return ""; + char c = line.charAt(pt); + switch (c) { + case '\'': + case '"': + pt++; + break; + default: + c = ' '; + line += " "; + } + int pt1 = line.indexOf(c, pt); + return (pt1 < 0 ? null : line.substring(pt, pt1)); + } + + /** * CSV format -- escaped quote is "" WITHIN "..." * * @@ -763,21 +790,21 @@ public class PT { return info instanceof Number || info instanceof Boolean; } - private static Object arrayGet(Object info, int i) { - /** - * - * Note that info will be a primitive in JavaScript - * but a wrapped primitive in Java. - * - * @j2sNative - * - * return info[i]; - */ - { - return Array.get(info, i); - } - } - +// private static Object arrayGet(Object info, int i) { +// /** +// * +// * Note that info will be a primitive in JavaScript +// * but a wrapped primitive in Java. +// * +// * @j2sNative +// * +// * return info[i]; +// */ +// { +// return Array.get(info, i); +// } +// } +// @SuppressWarnings("unchecked") public static String toJSON(String infoType, Object info) { if (info == null) @@ -855,7 +882,7 @@ public class PT { for (int i = 0; i < n; i++) { if (i > 0) sb.appendC(','); - sb.append(toJSON(null, arrayGet(info, i))); + sb.append(toJSON(null, Array.get(info, i))); } sb.append("]"); break; @@ -876,7 +903,7 @@ public class PT { /** * @j2sNative * - * return (x.constructor == Array || x.__BYTESIZE ? null : x.toString()); + * return (x.constructor == Array || x.BYTES_PER_ELEMENT ? null : x.toString()); * */ { diff --git a/src/javajs/util/Quat.java b/src/javajs/util/Quat.java index 5777308..d4a7bf9 100644 --- a/src/javajs/util/Quat.java +++ b/src/javajs/util/Quat.java @@ -524,7 +524,7 @@ public class Quat { * @return 0 <= angle <= 180 in degrees */ public float getTheta() { - return (float) (Math.acos(Math.abs(q0)) * (2 * 180 / Math.PI)); + return (float) (Math.acos(Math.abs(q0)) * 2 * 180 / Math.PI); } public float getThetaRadians() { diff --git a/src/javajs/util/Rdr.java b/src/javajs/util/Rdr.java index c357581..995a629 100644 --- a/src/javajs/util/Rdr.java +++ b/src/javajs/util/Rdr.java @@ -43,7 +43,6 @@ import java.util.Map; import javajs.api.Interface; -import javajs.J2SIgnoreImport; import javajs.api.GenericCifDataParser; import javajs.api.GenericLineReader; import javajs.api.GenericZipTools; @@ -62,9 +61,28 @@ import javajs.api.GenericZipTools; * * */ -@J2SIgnoreImport(BufferedWriter.class) public class Rdr implements GenericLineReader { + public static class StreamReader extends BufferedReader { + + private BufferedInputStream stream; + + public StreamReader(BufferedInputStream bis, String charSet) throws UnsupportedEncodingException { + super(new InputStreamReader(bis, (charSet == null ? "UTF-8" : charSet))); + stream = bis; + } + + public BufferedInputStream getStream() { + try { + stream.reset(); + } catch (IOException e) { + // ignore + } + return stream; + } + + } + BufferedReader reader; public Rdr(BufferedReader reader) { @@ -89,7 +107,7 @@ public class Rdr implements GenericLineReader { * Read a UTF-8 byte array fully, converting it to a String. * Called by Jmol's XMLReaders * - * @param bis + * @param bytes * @return a UTF-8 string */ public static String bytesToUTF8String(byte[] bytes) { @@ -126,7 +144,7 @@ public class Rdr implements GenericLineReader { throws IOException { // could also just make sure we have a buffered input stream here. if (getUTFEncodingForStream(bis) == Encoding.NONE) - return new BufferedReader(new InputStreamReader(bis, (charSet == null ? "UTF-8" : charSet))); + return new StreamReader(bis, (charSet == null ? "UTF-8" : charSet)); byte[] bytes = getLimitedStreamBytes(bis, -1); bis.close(); return getBR(charSet == null ? fixUTF(bytes) : new String(bytes, charSet)); @@ -136,7 +154,7 @@ public class Rdr implements GenericLineReader { * This method is specifically for strings that are marked for UTF 8 or 16. * * @param bytes - * @return + * @return UTF-decoded bytes */ public static String fixUTF(byte[] bytes) { Encoding encoding = getUTFEncoding(bytes); @@ -181,14 +199,14 @@ public class Rdr implements GenericLineReader { private static Encoding getUTFEncodingForStream(BufferedInputStream is) throws IOException { - /** - * @j2sNative - * - * is.resetStream(); - * - */ - { - } +// /** +// * @j2sNative +// * +// * is.resetStream(); +// * +// */ +// { +// } byte[] abMagic = new byte[4]; abMagic[3] = 1; try{ @@ -217,10 +235,19 @@ public class Rdr implements GenericLineReader { && (bytes[7] & 0xFF) == 0xE1); } + public static boolean isBZip2S(InputStream is) { + return isBZip2B(getMagic(is, 3)); + } + public static boolean isGzipS(InputStream is) { return isGzipB(getMagic(is, 2)); } + public static boolean isBZip2B(byte[] bytes) { + return (bytes != null && bytes.length >= 3 // BZh + && (bytes[0] & 0xFF) == 0x42 && (bytes[1] & 0xFF) == 0x5A && (bytes[2] & 0xFF) == 0x68); +} + public static boolean isGzipB(byte[] bytes) { return (bytes != null && bytes.length >= 2 && (bytes[0] & 0xFF) == 0x1F && (bytes[1] & 0xFF) == 0x8B); @@ -236,12 +263,16 @@ public class Rdr implements GenericLineReader { } public static boolean isMessagePackS(InputStream is) { - return isMessagePackB(getMagic(is, 1)); + return isMessagePackB(getMagic(is, 2)); } public static boolean isMessagePackB(byte[] bytes) { - // look for 'map' start - return (bytes != null && bytes.length >= 1 && (bytes[0] & 0xFF) == 0xDE); + // look for 'map' start, but PNG files start with 0x89, which is + // the MessagePack start for a 9-member map, so in that case we have + // to check that the next byte is not "P" as in <89>PNG + int b; + + return (bytes != null && bytes.length >= 1 && (((b = bytes[0] & 0xFF)) == 0xDE || (b & 0xE0) == 0x80 && bytes[1] != 0x50)); } public static boolean isPngZipStream(InputStream is) { @@ -253,6 +284,11 @@ public class Rdr implements GenericLineReader { return (bytes[50] == 0 && bytes[51] == 0x50 && bytes[52] == 0x4E && bytes[53] == 0x47 && bytes[54] == 0x4A); } + /** + * Check for a ZIP input stream - starting with "PK<03><04>" + * @param is + * @return true if a ZIP stream + */ public static boolean isZipS(InputStream is) { return isZipB(getMagic(is, 4)); } @@ -266,15 +302,15 @@ public class Rdr implements GenericLineReader { } public static byte[] getMagic(InputStream is, int n) { - byte[] abMagic = new byte[n]; - /** - * @j2sNative - * - * is.resetStream(); - * - */ - { - } + byte[] abMagic = new byte[n]; +// /** +// * @j2sNative +// * +// * is.resetStream(); +// * +// */ +// { +// } try { is.mark(n + 1); is.read(abMagic, 0, n); @@ -314,6 +350,14 @@ public class Rdr implements GenericLineReader { return new BufferedReader(new StringReader(string)); } + + public static BufferedInputStream toBIS(Object o) { + return (AU.isAB(o) ? getBIS((byte[]) o) + : o instanceof SB ? getBIS(Rdr.getBytesFromSB((SB) o)) + : o instanceof String ? getBIS(((String) o).getBytes()) : null); + } + + /** * Drill down into a GZIP stack until no more layers. * @param jzt @@ -329,6 +373,14 @@ public class Rdr implements GenericLineReader { return bis; } + public static BufferedInputStream getUnzippedInputStreamBZip2(GenericZipTools jzt, + BufferedInputStream bis) throws IOException { + while (isBZip2S(bis)) + bis = new BufferedInputStream(jzt.newBZip2InputStream(bis)); + return bis; + } + + /** * Allow for base64-encoding check. * @@ -544,7 +596,9 @@ public class Rdr implements GenericLineReader { public static BufferedWriter getBufferedWriter(OutputStream os, String charSetName) { OutputStreamWriter osw = (OutputStreamWriter) Interface.getInstanceWithParams("java.io.OutputStreamWriter", - new Class[] { java.io.OutputStream.class, String.class }, new Object[] {os, charSetName}); + new Class[] { java.io.OutputStream.class, String.class }, + new Object[] { os, charSetName == null ? "UTF-8" : charSetName } + ); /** * @j2sNative * return osw.getBufferedWriter(); diff --git a/src/javajs/util/SB.java b/src/javajs/util/SB.java index 578acf4..aed71f3 100644 --- a/src/javajs/util/SB.java +++ b/src/javajs/util/SB.java @@ -3,8 +3,6 @@ package javajs.util; import java.nio.charset.Charset; -import javajs.J2SIgnoreImport; - /** * Interesting thing here is that JavaScript is 3x faster than Java in handling strings. * @@ -14,7 +12,6 @@ import javajs.J2SIgnoreImport; * */ -@J2SIgnoreImport({java.lang.StringBuilder.class, java.nio.charset.Charset.class}) public class SB { private java.lang.StringBuilder sb; @@ -310,8 +307,8 @@ public class SB { } /** - * simple byte conversion properly implementing UTF-8. - * Used for base64 conversion and allows for offset + * simple byte conversion properly implementing UTF-8. * Used for base64 + * conversion and allows for offset * * @param off * @param len diff --git a/src/javajs/util/T3.java b/src/javajs/util/T3.java index bac7404..6cd5108 100644 --- a/src/javajs/util/T3.java +++ b/src/javajs/util/T3.java @@ -16,6 +16,8 @@ */ package javajs.util; +import java.io.Serializable; + import javajs.api.JSONEncodable; /** @@ -28,13 +30,15 @@ import javajs.api.JSONEncodable; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 * for unique constructor and method names - * for the optimization of compiled JavaScript using Java2Script. - * + * for the optimization of compiled JavaScript using Java2Script */ -public abstract class T3 implements JSONEncodable { +public abstract class T3 implements JSONEncodable, Serializable { public float x, y, z; + public T3() { + } + /** * Sets the value of this tuple to the specified xyz coordinates. * @@ -296,7 +300,7 @@ public abstract class T3 implements JSONEncodable { return (int) (bits ^ (bits >> 32)); } - static int floatToIntBits(float x) { + public static int floatToIntBits(float x) { return (x == 0 ? 0 : Float.floatToIntBits(x)); } diff --git a/src/javajs/util/T3d.java b/src/javajs/util/T3d.java index 549b3df..08d02d7 100644 --- a/src/javajs/util/T3d.java +++ b/src/javajs/util/T3d.java @@ -16,6 +16,8 @@ */ package javajs.util; +import java.io.Serializable; + /** * A generic 3 element tuple that is represented by double precision floating * point x,y and z coordinates. @@ -26,10 +28,9 @@ package javajs.util; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 * for unique constructor and method names - * for the optimization of compiled JavaScript using Java2Script. - * + * for the optimization of compiled JavaScript using Java2Script */ -public abstract class T3d { +public abstract class T3d implements Serializable { /** * The x coordinate. */ diff --git a/src/javajs/util/T3i.java b/src/javajs/util/T3i.java index fc9fd96..7fbd3bb 100644 --- a/src/javajs/util/T3i.java +++ b/src/javajs/util/T3i.java @@ -16,6 +16,8 @@ */ package javajs.util; +import java.io.Serializable; + /** * A 3-element tuple represented by signed integer x,y,z coordinates. * @@ -26,10 +28,9 @@ package javajs.util; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 for unique * constructor and method names for the optimization of compiled - * JavaScript using Java2Script. - * + * JavaScript using Java2Script */ -public abstract class T3i { +public abstract class T3i implements Serializable { /** * The x coordinate. diff --git a/src/javajs/util/T4.java b/src/javajs/util/T4.java index 535dd08..21b2741 100644 --- a/src/javajs/util/T4.java +++ b/src/javajs/util/T4.java @@ -26,8 +26,7 @@ package javajs.util; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 * for unique constructor and method names - * for the optimization of compiled JavaScript using Java2Script. - * + * for the optimization of compiled JavaScript using Java2Script */ public abstract class T4 extends T3 { @@ -37,6 +36,13 @@ public abstract class T4 extends T3 { public float w; /** + * Constructs and initializes a Tuple4f to (0,0,0,0). + * + */ + public T4() { + } + + /** * Sets the value of this tuple to the specified xyzw coordinates. * * @param x diff --git a/src/javajs/util/V3.java b/src/javajs/util/V3.java index edc8451..51325d2 100644 --- a/src/javajs/util/V3.java +++ b/src/javajs/util/V3.java @@ -28,11 +28,13 @@ package javajs.util; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 * for unique constructor and method names - * for the optimization of compiled JavaScript using Java2Script. - * + * for the optimization of compiled JavaScript using Java2Script */ public class V3 extends T3 { + public V3() { + } + public static V3 newV(T3 t) { return V3.new3(t.x, t.y, t.z); } diff --git a/src/javajs/util/V3d.java b/src/javajs/util/V3d.java index 78b5a82..9060575 100644 --- a/src/javajs/util/V3d.java +++ b/src/javajs/util/V3d.java @@ -30,8 +30,7 @@ package javajs.util; * * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 * for unique constructor and method names - * for the optimization of compiled JavaScript using Java2Script. - * + * for the optimization of compiled JavaScript using Java2Script */ public class V3d extends T3d { diff --git a/src/javajs/util/ZipData.java b/src/javajs/util/ZipData.java index 03a903b..f20715f 100644 --- a/src/javajs/util/ZipData.java +++ b/src/javajs/util/ZipData.java @@ -3,9 +3,6 @@ * $Date$ * $Revision$ * - * Some portions of this file have been modified by Robert Hanson hansonr.at.stolaf.edu 2012-2017 - * for use in SwingJS via transpilation into JavaScript using Java2Script. - * * Copyright (C) 2006 The Jmol Development Team * * Contact: jmol-developers@lists.sf.net diff --git a/src/javajs/util/ZipTools.java b/src/javajs/util/ZipTools.java index 6714236..a4082ec 100644 --- a/src/javajs/util/ZipTools.java +++ b/src/javajs/util/ZipTools.java @@ -32,12 +32,6 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; - -import javajs.J2SIgnoreImport; -import javajs.api.GenericZipInputStream; -import javajs.api.GenericZipTools; -import javajs.api.ZInputStream; - import java.util.Map; import java.util.zip.CRC32; import java.util.zip.GZIPInputStream; @@ -45,12 +39,18 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; +import javajs.api.GenericZipInputStream; +import javajs.api.GenericZipTools; +import javajs.api.Interface; +import javajs.api.ZInputStream; + +import org.apache.tools.bzip2.CBZip2InputStreamFactory; + /** * Note the JSmol/HTML5 must use its own version of java.util.zip.ZipOutputStream. * */ -@J2SIgnoreImport({ java.util.zip.ZipOutputStream.class }) public class ZipTools implements GenericZipTools { public ZipTools() { @@ -62,6 +62,7 @@ public class ZipTools implements GenericZipTools { return newZIS(is); } + @SuppressWarnings("resource") private static ZInputStream newZIS(InputStream is) { return (is instanceof ZInputStream ? (ZInputStream) is : is instanceof BufferedInputStream ? new GenericZipInputStream(is) @@ -286,6 +287,11 @@ public class ZipTools implements GenericZipTools { } @Override + public InputStream newBZip2InputStream(InputStream is) throws IOException { + return new BufferedInputStream(((CBZip2InputStreamFactory) Interface.getInterface("org.apache.tools.bzip2.CBZip2InputStreamFactory")).getStream(is)); + } + + @Override public BufferedInputStream getUnGzippedInputStream(byte[] bytes) { try { return Rdr.getUnzippedInputStream(this, Rdr.getBIS(bytes)); @@ -306,16 +312,16 @@ public class ZipTools implements GenericZipTools { @Override public Object getZipOutputStream(Object bos) { - /** - * @j2sNative - * - * return javajs.api.Interface.getInterface( - * "java.util.zip.ZipOutputStream").setZOS(bos); - * - */ - { +// /** +// * @j2sNative +// * +// * return javajs.api.Interface.getInterface( +// * "java.util.zip.ZipOutputStream").setZOS(bos); +// * +// */ +// { return new ZipOutputStream((OutputStream) bos); - } +// } } @Override @@ -353,9 +359,9 @@ public class ZipTools implements GenericZipTools { bdata.clear(); bdata.put("_ERROR_", e.getMessage()); } - } + } - @Override + @Override public String cacheZipContents(BufferedInputStream bis, String fileName, Map cache, @@ -419,9 +425,9 @@ public class ZipTools implements GenericZipTools { return null; System.out.println("ZipTools cached " + n + " bytes from " + fileName); return listing.toString(); - } + } - private static byte[] getPngImageBytes(BufferedInputStream bis) { + private static byte[] getPngImageBytes(BufferedInputStream bis) { try { if (Rdr.isPngZipStream(bis)) { int pt_count[] = new int[2]; diff --git a/src/org/apache/harmony/luni/util/ExternalMessages.properties b/src/org/apache/harmony/luni/util/ExternalMessages.properties new file mode 100644 index 0000000..54227b8 --- /dev/null +++ b/src/org/apache/harmony/luni/util/ExternalMessages.properties @@ -0,0 +1,311 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# External Messages for EN locale +K0006=Negative index specified +K0007=attempt to write after finish +K0008=Cannot read version +K0009=Missing version string\: {0} +K000a=Entry is not named +K000b=Invalid attribute {0} +K000c=cannot resolve subclasses +K000d=Unknown attribute +K000e=Cannot add attributes to empty string +K0014=Unquoted {0} in suffix\: {1} +K0015=Unexpected {0} in fraction\: {1} +K0016=Unexpected {0} in {1} +K0017=Missing pattern before {0} in {1} +K0018=Missing exponent format {0} +K0019=Unterminated quote {0} +K001a=Missing grouping format {0} +K001b=Invalid exponent format {0} +K001c=Invalid pattern char {0} in {1} +K001d=Invalid argument number +K001e=Missing element format +K001f=Unknown element format +K0020=Unknown format +K002b=Unknown pattern character - '{0}' +K002c=Access denied {0} +K002e=Offset out of bounds +K002f=Arguments out of bounds +K0032=Address null or destination port out of range +K0033=Unknown socket type +K0034=Packet address mismatch with connected address +K0035=Zero or negative buffer size +K0036=Invalid negative timeout +K0037=Connection already established +K0038=No host name provided +K0039=Attempted to join a non-multicast group +K003a=Attempted to leave a non-multicast group +K003c=TimeToLive out of bounds +K003d=Socket is closed +K003e=SOCKS connection failed\: {0} +K003f=Unable to connect to SOCKS server\: {0} +K0040=Invalid SOCKS client. +K0041=Socket implementation does not support SOCKS. +K0042=Socket implementation factory already set +K0044=The factory has already been set +K0045=Attempted to set a negative SoLinger +K0046=Local port declared out of range +K0047=buffer is null +K0048=Invalid action specified\: {0} +K0049=MinPort is greater than MaxPort +K004a=Invalid port number specified +K004b=Attempt to set factory more than once. +K004c=Package is sealed +K004d=Does not support writing to the input stream +K004e=Duplicate Factory +K004f=rounding necessary +K0050=wrong rounding mode +K0051=scale value < than zero +K0052=Array index out of range\: {0} +K0053=Package {0} already defined. +K0055=String index out of range\: {0} +K0056=Already destroyed +K0057=Has threads +K0058=size must be > 0 +K0059=Stream is closed +K005a=Mark has been invalidated. +K005b=BufferedReader is closed +K005c=Invalid Mark. +K005d=Writer is closed. +K005e=size must be >\= 0 +K005f=Does not support writing to the output stream +K0060=CharArrayReader is closed. +K0062=Second byte at {0} does not match UTF8 Specification +K0063=Third byte at {0} does not match UTF8 Specification +K0064=Second or third byte at {0} does not match UTF8 Specification +K0065=Input at {0} does not match UTF8 Specification +K0066=Entry already exists: {0} +K0068=String is too long +K0069=File cannot compare to non File +K006a=time must be positive +K006b=Prefix must be at least 3 characters +K006c=FileDescriptor is null +K006d=actions invalid +K006e=path is null +K006f=invalid permission\: {0} +K0070=InputStreamReader is closed. +K0071=Error fetching SUID\: {0} +K0072={0} computing SHA-1 / SUID +K0073=OutputStreamWriter is closed. +K0074=Not connected +K0075=InputStream is closed +K0076=Pipe broken +K0077=Crc mismatch +K0078=Pipe is closed +K0079=Already connected +K007a=Pipe already connected +K007b=Pipe Not Connected +K007e=Pushback buffer full +K007f=Mark/Reset not supported +K0080=Reader is closed +K0081=Mode must be one of "r" or "rw" +K0083=StringReader is closed. +K0084=can only instantiate one BootstrapClassLoader +K0086=Referenced reflect object is no longer valid +K0087=Referenced reflect object is no longer valid\: {0} +K0088=Incorrect end of BER tag +K0089=Unknown type\: {0} +K008a=Read {0} bytes trying to read {1} bytes from {2} +K008b=Position\: {0} +K008c=Invalid Base64 char\:{0} +K008d=This protocol does not support input +K008e=Does not support output +K008f=This method does not support writing\: {0} +K0090=can't open OutputStream after reading from an inputStream +K0091=Cannot access request header fields after connection is set +K0092=Cannot set method after connection is made +K0093=Too many redirects +K0094=Unable to change directories +K0095=Could not establish data connection +K0096=Unable to retrieve file\: {0} +K0097=Unable to connect to server\: {0} +K0098=Unable to log into server\: {0} +K0099=Unable to configure data port +K009a=Unable to store file +K009b=Unable to set transfer type +K00a2=Parsing policy file\: {0}, expected quoted {1}, found unquoted\: {2} +K00a3=Parsing policy file\: {0}, found unexpected\: {1} +K00a4=Content-Length underflow +K00a5=Invalid parameter - {0} +K00a8=Parsing policy file\: {0}, invalid codesource URL\: {1} +K00ab=No active entry +K00ae=Size mismatch +K00af=Invalid proxy port\: {0} +K00b0=Proxy port out of range +K00b1=Invalid port number +K00b2=Content-Length exceeded +K00b3=Unknown protocol\: {0} +K00b6=No entries +K00b7=File is closed +K00c1=Illegal character +K00cd=Failure to connect to SOCKS server. +K00ce=Unable to connect to identd to verify user. +K00cf=Failure - user ids do not match. +K00d0=Success +K00d1=Read null attempting to read class descriptor for an object +K00d2=Wrong format\: 0x{0} +K00d3=Read an exception +K00d4={2} - {0} not compatible with {1} +K00d5=Invalid typecode\: {0} +K00d7=Wrong base type in\: {0} +K00d8=Protocol not found\: {0} +K00d9=Callback object cannot be null +K00da=Incompatible class (SUID)\: {0} but expected {1} +K00dc=IllegalAccessException +K00e3=Could not create specified security manager\: {0} +K00e4=Key usage is critical and cannot be used for digital signature purposes. +K00e5=month\: {0} +K00e6=day of month\: {0} +K00e7=day of week\: {0} +K00e8=time\: {0} +K00e9=DST offset\: {0} +K00ea=era\: {0} +K00eb={0} failed verification of {1} +K00ec={0} has invalid digest for {1} in {2} +K00ed={0} is not an interface +K00ee={0} is not visible from class loader +K00ef={0} appears more than once +K00f0=non-public interfaces must be in the same package +K00f1=not a proxy instance +K00f2=the methods named {0} must have the same return type +K00f3=Timer was cancelled +K00f5=Illegal delay to start the TimerTask +K00f6=TimerTask is scheduled already +K00f7=TimerTask is cancelled +K00f8=day of week in month\: {0} +K00f9=min or max digit count too large +K00fa=min digits greater than max digits +K00fb=min or max digits negative +K00fc=Jar entry not specified +K00fd=Invalid keystore +K00fe=Incorrect password +K0185=The alias already exists for a key entry. +K018f=Can't convert to BMPString \: {0} +K0190=No data to decode +K0191=Invalid size, must be a multiple of 64 from 512 to 1024 +K0193=An identity with this name already exists in this scope +K0194=An identity in the scope has the same public key +K0195=The existing public key and the one contained in the certificate do not match. +K0196=Certificate is missing +K0199=Count out of range +K01a0=End of stream condition +K01a4=Already shutting down +K01a5=Illegal shutdown hook\: {0} +K01a6=Invalid filter +K01a7=Name too long: {0} +K01b3=Incorrect number of arguments +K01b4=Cannot convert {0} to {1} +K01b6=Cannot find \!/ +K01c1=File is a Directory +K01c2=Cannot create\: {0} +K01c3=Unable to open\: {0} +K01c4=Invalid zip file\: {0} +K01c6=No Main-Class specified in manifest\: {0} +K01d1=Signers of '{0}' do not match signers of other classes in package +K01d2={1} - protected system package '{0}' +K01ec=key size must be a multiple of 8 bits +K01ed=key size must be at least 512 bits +K01fe=Incomplete % sequence at\: {0} +K01ff=Invalid % sequence ({0}) at\: {1} +K0220=UTFDataFormatException +K0222=No Manifest found in jar file\: {0} +K0300=Unsupported encoding +K0301=Not signed data +K0302=Relative path +K0303=Scheme-specific part expected +K0304=Authority expected +K0305=Illegal character in scheme +K0306={0} in schemeSpecificPart +K0307={0} in authority +K0308={0} in path +K0309={0} in query +K030a={0} in fragment +K030c=Expected host +K030d=Illegal character in userinfo +K030e=Expected a closing square bracket for ipv6 address +K030f=Malformed ipv6 address +K0310=Illegal character in host name +K0311=Malformed ipv4 address +K0312=URI is not absolute +K0313=Incomplete % sequence +K0314=Invalid % sequence ({0}) +K0315=Socket is already bound +K0316=SocketAddress {0} not supported +K0317=Host is unresolved\: {0} +K0318=SocketAddress is null +K0319=Exception in thread "{0}"\ +K031a=URI is not absolute\: {0} +K031b=URI is not hierarchical\: {0} +K031c=Expected file scheme in URI\: {0} +K031d=Expected non-empty path in URI\: {0} +K031e=Found {0} component in URI\: {1} +K031f=Socket is not bound +K0320=Socket is not connected +K0321=Socket input is shutdown +K0322=Not a supported ISO 4217 Currency Code\: {0} +K0323=Not a supported ISO 3166 Country locale\: {0} +K0324=Needs dictionary +K0325=Port out of range\: {0} +K0326={0} at index {1}\: {2} +K0327={0}\: {1} +K0328=Certificate not yet valid +K0329=Certificate expired +K0330=interface name is null +K0331=address is null +K0332=Invalid IP Address is neither 4 or 16 bytes\: {0} +K0333=Urgent data not supported +K0334=Cannot set network interface with null +K0335=No addresses associated with Interface +K0337=null type not allowed +K0338=Address not associated with an interface - not set +K0339=Invalid IP Address is neither 4 or 16 bytes +K0340={0} incompatible with {1} +K0342=Scheme expected +K0344=Not a valid {0}, subclass should override readResolve() +K0346=Unmatched braces in the pattern +K0347=seek position is negative +K0348=Format specifier '{0}' +K0349=Conversion is '{0}' +K034a=The flags are {0} +K034b=url and proxy can not be null +K034c=proxy should not be null +K034d=method has not been implemented yet +K034e=Build rules empty +K0351=format is null +KA000=Line too long +KA001=Argument must not be null +KA002=Unshared read of back reference +KA003=different mode already set +KA004=Enums may not be cloned +KA005={0} is not an enum type +KA006={0} is not a constant in the enum type {1} +KA007=field is null +KA008={0} is an illegal radix +KA009=CharsetName is illegal +KA00a=File is null +KA00b=InputStream is null +KA00c=Readable is null +KA00d=ReadableByteChannel is null +KA00e=Radix {0} is less than Character.MIN_RADIX or greater than Character.MAX_RADIX +KA00f=Socket output is shutdown +KA010=Cannot read back reference to unshared object +KA011=Malformed reply from SOCKS server +KA012=No such file or directory +KA013=Number of bytes to skip cannot be negative +KA014=Invalit UUID string +KA015=Incompatible class (base name)\: {0} but expected {1} + diff --git a/src/org/apache/harmony/luni/util/ExternalMessages.properties.js b/src/org/apache/harmony/luni/util/ExternalMessages.properties.js new file mode 100644 index 0000000..cf6a86e --- /dev/null +++ b/src/org/apache/harmony/luni/util/ExternalMessages.properties.js @@ -0,0 +1 @@ +java.util.ResourceBundle.registerBundle("org.apache.harmony.luni.util.ExternalMessages", "K0006=Negative index specified\r\nK0007=attempt to write after finish\r\nK0008=Cannot read version\r\nK0009=Missing version string\\: {0}\r\nK000a=Entry is not named\r\nK000b=Invalid attribute {0}\r\nK000c=cannot resolve subclasses\r\nK000d=Unknown attribute\r\nK000e=Cannot add attributes to empty string\r\nK0014=Unquoted {0} in suffix\\: {1}\r\nK0015=Unexpected {0} in fraction\\: {1}\r\nK0016=Unexpected {0} in {1}\r\nK0017=Missing pattern before {0} in {1}\r\nK0018=Missing exponent format {0}\r\nK0019=Unterminated quote {0}\r\nK001a=Missing grouping format {0}\r\nK001b=Invalid exponent format {0}\r\nK001c=Invalid pattern char {0} in {1}\r\nK001d=Invalid argument number\r\nK001e=Missing element format\r\nK001f=Unknown element format\r\nK0020=Unknown format\r\nK002b=Unknown pattern character - \'{0}\'\r\nK002c=Access denied {0}\r\nK002e=Offset out of bounds\r\nK002f=Arguments out of bounds\r\nK0032=Address null or destination port out of range\r\nK0033=Unknown socket type\r\nK0034=Packet address mismatch with connected address\r\nK0035=Zero or negative buffer size\r\nK0036=Invalid negative timeout\r\nK0037=Connection already established\r\nK0038=No host name provided\r\nK0039=Attempted to join a non-multicast group\r\nK003a=Attempted to leave a non-multicast group\r\nK003c=TimeToLive out of bounds\r\nK003d=Socket is closed\r\nK003e=SOCKS connection failed\\: {0}\r\nK003f=Unable to connect to SOCKS server\\: {0}\r\nK0040=Invalid SOCKS client.\r\nK0041=Socket implementation does not support SOCKS.\r\nK0042=Socket implementation factory already set\r\nK0044=The factory has already been set\r\nK0045=Attempted to set a negative SoLinger\r\nK0046=Local port declared out of range\r\nK0047=buffer is null\r\nK0048=Invalid action specified\\: {0}\r\nK0049=MinPort is greater than MaxPort\r\nK004a=Invalid port number specified\r\nK004b=Attempt to set factory more than once.\r\nK004c=Package is sealed\r\nK004d=Does not support writing to the input stream\r\nK004e=Duplicate Factory\r\nK004f=rounding necessary\r\nK0050=wrong rounding mode\r\nK0051=scale value < than zero\r\nK0052=Array index out of range\\: {0}\r\nK0053=Package {0} already defined.\r\nK0055=String index out of range\\: {0}\r\nK0056=Already destroyed\r\nK0057=Has threads\r\nK0058=size must be > 0\r\nK0059=Stream is closed\r\nK005a=Mark has been invalidated.\r\nK005b=BufferedReader is closed\r\nK005c=Invalid Mark.\r\nK005d=Writer is closed.\r\nK005e=size must be >\\= 0\r\nK005f=Does not support writing to the output stream\r\nK0060=CharArrayReader is closed.\r\nK0062=Second byte at {0} does not match UTF8 Specification\r\nK0063=Third byte at {0} does not match UTF8 Specification\r\nK0064=Second or third byte at {0} does not match UTF8 Specification\r\nK0065=Input at {0} does not match UTF8 Specification\r\nK0066=Entry already exists: {0}\r\nK0068=String is too long\r\nK0069=File cannot compare to non File\r\nK006a=time must be positive\r\nK006b=Prefix must be at least 3 characters\r\nK006c=FileDescriptor is null\r\nK006d=actions invalid\r\nK006e=path is null\r\nK006f=invalid permission\\: {0}\r\nK0070=InputStreamReader is closed.\r\nK0071=Error fetching SUID\\: {0}\r\nK0072={0} computing SHA-1 / SUID\r\nK0073=OutputStreamWriter is closed.\r\nK0074=Not connected\r\nK0075=InputStream is closed\r\nK0076=Pipe broken\r\nK0077=Crc mismatch\r\nK0078=Pipe is closed\r\nK0079=Already connected\r\nK007a=Pipe already connected\r\nK007b=Pipe Not Connected\r\nK007e=Pushback buffer full\r\nK007f=Mark/Reset not supported\r\nK0080=Reader is closed\r\nK0081=Mode must be one of \"r\" or \"rw\"\r\nK0083=StringReader is closed.\r\nK0084=can only instantiate one BootstrapClassLoader\r\nK0086=Referenced reflect object is no longer valid\r\nK0087=Referenced reflect object is no longer valid\\: {0}\r\nK0088=Incorrect end of BER tag\r\nK0089=Unknown type\\: {0}\r\nK008a=Read {0} bytes trying to read {1} bytes from {2}\r\nK008b=Position\\: {0}\r\nK008c=Invalid Base64 char\\:{0}\r\nK008d=This protocol does not support input\r\nK008e=Does not support output\r\nK008f=This method does not support writing\\: {0}\r\nK0090=can\'t open OutputStream after reading from an inputStream\r\nK0091=Cannot access request header fields after connection is set\r\nK0092=Cannot set method after connection is made\r\nK0093=Too many redirects\r\nK0094=Unable to change directories\r\nK0095=Could not establish data connection\r\nK0096=Unable to retrieve file\\: {0}\r\nK0097=Unable to connect to server\\: {0}\r\nK0098=Unable to log into server\\: {0}\r\nK0099=Unable to configure data port\r\nK009a=Unable to store file\r\nK009b=Unable to set transfer type\r\nK00a2=Parsing policy file\\: {0}, expected quoted {1}, found unquoted\\: {2}\r\nK00a3=Parsing policy file\\: {0}, found unexpected\\: {1}\r\nK00a4=Content-Length underflow\r\nK00a5=Invalid parameter - {0}\r\nK00a8=Parsing policy file\\: {0}, invalid codesource URL\\: {1}\r\nK00ab=No active entry\r\nK00ae=Size mismatch\r\nK00af=Invalid proxy port\\: {0}\r\nK00b0=Proxy port out of range\r\nK00b1=Invalid port number\r\nK00b2=Content-Length exceeded\r\nK00b3=Unknown protocol\\: {0}\r\nK00b6=No entries\r\nK00b7=File is closed\r\nK00c1=Illegal character\r\nK00cd=Failure to connect to SOCKS server.\r\nK00ce=Unable to connect to identd to verify user.\r\nK00cf=Failure - user ids do not match.\r\nK00d0=Success\r\nK00d1=Read null attempting to read class descriptor for an object\r\nK00d2=Wrong format\\: 0x{0}\r\nK00d3=Read an exception\r\nK00d4={2} - {0} not compatible with {1}\r\nK00d5=Invalid typecode\\: {0}\r\nK00d7=Wrong base type in\\: {0}\r\nK00d8=Protocol not found\\: {0}\r\nK00d9=Callback object cannot be null\r\nK00da=Incompatible class (SUID)\\: {0} but expected {1}\r\nK00dc=IllegalAccessException\r\nK00e3=Could not create specified security manager\\: {0}\r\nK00e4=Key usage is critical and cannot be used for digital signature purposes.\r\nK00e5=month\\: {0}\r\nK00e6=day of month\\: {0}\r\nK00e7=day of week\\: {0}\r\nK00e8=time\\: {0}\r\nK00e9=DST offset\\: {0}\r\nK00ea=era\\: {0}\r\nK00eb={0} failed verification of {1}\r\nK00ec={0} has invalid digest for {1} in {2}\r\nK00ed={0} is not an interface\r\nK00ee={0} is not visible from class loader\r\nK00ef={0} appears more than once\r\nK00f0=non-public interfaces must be in the same package\r\nK00f1=not a proxy instance\r\nK00f2=the methods named {0} must have the same return type\r\nK00f3=Timer was cancelled\r\nK00f5=Illegal delay to start the TimerTask\r\nK00f6=TimerTask is scheduled already\r\nK00f7=TimerTask is cancelled\r\nK00f8=day of week in month\\: {0}\r\nK00f9=min or max digit count too large\r\nK00fa=min digits greater than max digits\r\nK00fb=min or max digits negative\r\nK00fc=Jar entry not specified\r\nK00fd=Invalid keystore\r\nK00fe=Incorrect password\r\nK0185=The alias already exists for a key entry.\r\nK018f=Can\'t convert to BMPString \\: {0}\r\nK0190=No data to decode\r\nK0191=Invalid size, must be a multiple of 64 from 512 to 1024\r\nK0193=An identity with this name already exists in this scope\r\nK0194=An identity in the scope has the same public key\r\nK0195=The existing public key and the one contained in the certificate do not match.\r\nK0196=Certificate is missing\r\nK0199=Count out of range\r\nK01a0=End of stream condition\r\nK01a4=Already shutting down\r\nK01a5=Illegal shutdown hook\\: {0}\r\nK01a6=Invalid filter\r\nK01a7=Name too long: {0}\r\nK01b3=Incorrect number of arguments\r\nK01b4=Cannot convert {0} to {1}\r\nK01b6=Cannot find \\!/\r\nK01c1=File is a Directory\r\nK01c2=Cannot create\\: {0}\r\nK01c3=Unable to open\\: {0}\r\nK01c4=Invalid zip file\\: {0}\r\nK01c6=No Main-Class specified in manifest\\: {0}\r\nK01d1=Signers of \'{0}\' do not match signers of other classes in package\r\nK01d2={1} - protected system package \'{0}\'\r\nK01ec=key size must be a multiple of 8 bits\r\nK01ed=key size must be at least 512 bits\r\nK01fe=Incomplete % sequence at\\: {0}\r\nK01ff=Invalid % sequence ({0}) at\\: {1}\r\nK0220=UTFDataFormatException\r\nK0222=No Manifest found in jar file\\: {0}\r\nK0300=Unsupported encoding\r\nK0301=Not signed data\r\nK0302=Relative path\r\nK0303=Scheme-specific part expected\r\nK0304=Authority expected\r\nK0305=Illegal character in scheme\r\nK0306={0} in schemeSpecificPart\r\nK0307={0} in authority\r\nK0308={0} in path\r\nK0309={0} in query\r\nK030a={0} in fragment\r\nK030c=Expected host\r\nK030d=Illegal character in userinfo\r\nK030e=Expected a closing square bracket for ipv6 address\r\nK030f=Malformed ipv6 address\r\nK0310=Illegal character in host name\r\nK0311=Malformed ipv4 address\r\nK0312=URI is not absolute\r\nK0313=Incomplete % sequence\r\nK0314=Invalid % sequence ({0})\r\nK0315=Socket is already bound\r\nK0316=SocketAddress {0} not supported\r\nK0317=Host is unresolved\\: {0}\r\nK0318=SocketAddress is null\r\nK0319=Exception in thread \"{0}\"\\ \r\nK031a=URI is not absolute\\: {0}\r\nK031b=URI is not hierarchical\\: {0}\r\nK031c=Expected file scheme in URI\\: {0}\r\nK031d=Expected non-empty path in URI\\: {0}\r\nK031e=Found {0} component in URI\\: {1}\r\nK031f=Socket is not bound\r\nK0320=Socket is not connected\r\nK0321=Socket input is shutdown\r\nK0322=Not a supported ISO 4217 Currency Code\\: {0}\r\nK0323=Not a supported ISO 3166 Country locale\\: {0}\r\nK0324=Needs dictionary\r\nK0325=Port out of range\\: {0}\r\nK0326={0} at index {1}\\: {2}\r\nK0327={0}\\: {1}\r\nK0328=Certificate not yet valid\r\nK0329=Certificate expired\r\nK0330=interface name is null\r\nK0331=address is null\r\nK0332=Invalid IP Address is neither 4 or 16 bytes\\: {0}\r\nK0333=Urgent data not supported\r\nK0334=Cannot set network interface with null\r\nK0335=No addresses associated with Interface\r\nK0337=null type not allowed\r\nK0338=Address not associated with an interface - not set\r\nK0339=Invalid IP Address is neither 4 or 16 bytes\r\nK0340={0} incompatible with {1}\r\nK0342=Scheme expected\r\nK0344=Not a valid {0}, subclass should override readResolve()\r\nK0346=Unmatched braces in the pattern\r\nK0347=seek position is negative\r\nK0348=Format specifier \'{0}\'\r\nK0349=Conversion is \'{0}\'\r\nK034a=The flags are {0}\r\nK034b=url and proxy can not be null\r\nK034c=proxy should not be null\r\nK034d=method has not been implemented yet\r\nK034e=Build rules empty\r\nK0351=format is null\r\nKA000=Line too long\r\nKA001=Argument must not be null\r\nKA002=Unshared read of back reference\r\nKA003=different mode already set\r\nKA004=Enums may not be cloned\r\nKA005={0} is not an enum type\r\nKA006={0} is not a constant in the enum type {1}\r\nKA007=field is null\r\nKA008={0} is an illegal radix\r\nKA009=CharsetName is illegal\r\nKA00a=File is null\r\nKA00b=InputStream is null\r\nKA00c=Readable is null\r\nKA00d=ReadableByteChannel is null\r\nKA00e=Radix {0} is less than Character.MIN_RADIX or greater than Character.MAX_RADIX\r\nKA00f=Socket output is shutdown\r\nKA010=Cannot read back reference to unshared object\r\nKA011=Malformed reply from SOCKS server\r\nKA012=No such file or directory\r\nKA013=Number of bytes to skip cannot be negative\r\nKA014=Invalit UUID string\r\nKA015=Incompatible class (base name)\\: {0} but expected {1}\r\n\r\n"); \ No newline at end of file diff --git a/src/org/apache/harmony/luni/util/Msg.java b/src/org/apache/harmony/luni/util/Msg.java new file mode 100644 index 0000000..d90ee77 --- /dev/null +++ b/src/org/apache/harmony/luni/util/Msg.java @@ -0,0 +1,228 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.util; + +/** + * This class retrieves strings from a resource bundle and returns them, + * formatting them with MessageFormat when required. + *

+ * It is used by the system classes to provide national language support, by + * looking up messages in the + * org.apache.harmony.luni.util.ExternalMessages + * + * resource bundle. Note that if this file is not available, or an invalid key + * is looked up, or resource bundle support is not available, the key itself + * will be returned as the associated message. This means that the KEY + * should a reasonable human-readable (english) string. + * + */ +public class Msg { + + final static String msgs = "K0006=Negative index specified\r\nK0007=attempt to write after finish\r\nK0008=Cannot read version\r\nK0009=Missing version string\\: {0}\r\nK000a=Entry is not named\r\nK000b=Invalid attribute {0}\r\nK000c=cannot resolve subclasses\r\nK000d=Unknown attribute\r\nK000e=Cannot add attributes to empty string\r\nK0014=Unquoted {0} in suffix\\: {1}\r\nK0015=Unexpected {0} in fraction\\: {1}\r\nK0016=Unexpected {0} in {1}\r\nK0017=Missing pattern before {0} in {1}\r\nK0018=Missing exponent format {0}\r\nK0019=Unterminated quote {0}\r\nK001a=Missing grouping format {0}\r\nK001b=Invalid exponent format {0}\r\nK001c=Invalid pattern char {0} in {1}\r\nK001d=Invalid argument number\r\nK001e=Missing element format\r\nK001f=Unknown element format\r\nK0020=Unknown format\r\nK002b=Unknown pattern character - \'{0}\'\r\nK002c=Access denied {0}\r\nK002e=Offset out of bounds\r\nK002f=Arguments out of bounds\r\nK0032=Address null or destination port out of range\r\nK0033=Unknown socket type\r\nK0034=Packet address mismatch with connected address\r\nK0035=Zero or negative buffer size\r\nK0036=Invalid negative timeout\r\nK0037=Connection already established\r\nK0038=No host name provided\r\nK0039=Attempted to join a non-multicast group\r\nK003a=Attempted to leave a non-multicast group\r\nK003c=TimeToLive out of bounds\r\nK003d=Socket is closed\r\nK003e=SOCKS connection failed\\: {0}\r\nK003f=Unable to connect to SOCKS server\\: {0}\r\nK0040=Invalid SOCKS client.\r\nK0041=Socket implementation does not support SOCKS.\r\nK0042=Socket implementation factory already set\r\nK0044=The factory has already been set\r\nK0045=Attempted to set a negative SoLinger\r\nK0046=Local port declared out of range\r\nK0047=buffer is null\r\nK0048=Invalid action specified\\: {0}\r\nK0049=MinPort is greater than MaxPort\r\nK004a=Invalid port number specified\r\nK004b=Attempt to set factory more than once.\r\nK004c=Package is sealed\r\nK004d=Does not support writing to the input stream\r\nK004e=Duplicate Factory\r\nK004f=rounding necessary\r\nK0050=wrong rounding mode\r\nK0051=scale value < than zero\r\nK0052=Array index out of range\\: {0}\r\nK0053=Package {0} already defined.\r\nK0055=String index out of range\\: {0}\r\nK0056=Already destroyed\r\nK0057=Has threads\r\nK0058=size must be > 0\r\nK0059=Stream is closed\r\nK005a=Mark has been invalidated.\r\nK005b=BufferedReader is closed\r\nK005c=Invalid Mark.\r\nK005d=Writer is closed.\r\nK005e=size must be >\\= 0\r\nK005f=Does not support writing to the output stream\r\nK0060=CharArrayReader is closed.\r\nK0062=Second byte at {0} does not match UTF8 Specification\r\nK0063=Third byte at {0} does not match UTF8 Specification\r\nK0064=Second or third byte at {0} does not match UTF8 Specification\r\nK0065=Input at {0} does not match UTF8 Specification\r\nK0066=Entry already exists: {0}\r\nK0068=String is too long\r\nK0069=File cannot compare to non File\r\nK006a=time must be positive\r\nK006b=Prefix must be at least 3 characters\r\nK006c=FileDescriptor is null\r\nK006d=actions invalid\r\nK006e=path is null\r\nK006f=invalid permission\\: {0}\r\nK0070=InputStreamReader is closed.\r\nK0071=Error fetching SUID\\: {0}\r\nK0072={0} computing SHA-1 / SUID\r\nK0073=OutputStreamWriter is closed.\r\nK0074=Not connected\r\nK0075=InputStream is closed\r\nK0076=Pipe broken\r\nK0077=Crc mismatch\r\nK0078=Pipe is closed\r\nK0079=Already connected\r\nK007a=Pipe already connected\r\nK007b=Pipe Not Connected\r\nK007e=Pushback buffer full\r\nK007f=Mark/Reset not supported\r\nK0080=Reader is closed\r\nK0081=Mode must be one of \"r\" or \"rw\"\r\nK0083=StringReader is closed.\r\nK0084=can only instantiate one BootstrapClassLoader\r\nK0086=Referenced reflect object is no longer valid\r\nK0087=Referenced reflect object is no longer valid\\: {0}\r\nK0088=Incorrect end of BER tag\r\nK0089=Unknown type\\: {0}\r\nK008a=Read {0} bytes trying to read {1} bytes from {2}\r\nK008b=Position\\: {0}\r\nK008c=Invalid Base64 char\\:{0}\r\nK008d=This protocol does not support input\r\nK008e=Does not support output\r\nK008f=This method does not support writing\\: {0}\r\nK0090=can\'t open OutputStream after reading from an inputStream\r\nK0091=Cannot access request header fields after connection is set\r\nK0092=Cannot set method after connection is made\r\nK0093=Too many redirects\r\nK0094=Unable to change directories\r\nK0095=Could not establish data connection\r\nK0096=Unable to retrieve file\\: {0}\r\nK0097=Unable to connect to server\\: {0}\r\nK0098=Unable to log into server\\: {0}\r\nK0099=Unable to configure data port\r\nK009a=Unable to store file\r\nK009b=Unable to set transfer type\r\nK00a2=Parsing policy file\\: {0}, expected quoted {1}, found unquoted\\: {2}\r\nK00a3=Parsing policy file\\: {0}, found unexpected\\: {1}\r\nK00a4=Content-Length underflow\r\nK00a5=Invalid parameter - {0}\r\nK00a8=Parsing policy file\\: {0}, invalid codesource URL\\: {1}\r\nK00ab=No active entry\r\nK00ae=Size mismatch\r\nK00af=Invalid proxy port\\: {0}\r\nK00b0=Proxy port out of range\r\nK00b1=Invalid port number\r\nK00b2=Content-Length exceeded\r\nK00b3=Unknown protocol\\: {0}\r\nK00b6=No entries\r\nK00b7=File is closed\r\nK00c1=Illegal character\r\nK00cd=Failure to connect to SOCKS server.\r\nK00ce=Unable to connect to identd to verify user.\r\nK00cf=Failure - user ids do not match.\r\nK00d0=Success\r\nK00d1=Read null attempting to read class descriptor for an object\r\nK00d2=Wrong format\\: 0x{0}\r\nK00d3=Read an exception\r\nK00d4={2} - {0} not compatible with {1}\r\nK00d5=Invalid typecode\\: {0}\r\nK00d7=Wrong base type in\\: {0}\r\nK00d8=Protocol not found\\: {0}\r\nK00d9=Callback object cannot be null\r\nK00da=Incompatible class (SUID)\\: {0} but expected {1}\r\nK00dc=IllegalAccessException\r\nK00e3=Could not create specified security manager\\: {0}\r\nK00e4=Key usage is critical and cannot be used for digital signature purposes.\r\nK00e5=month\\: {0}\r\nK00e6=day of month\\: {0}\r\nK00e7=day of week\\: {0}\r\nK00e8=time\\: {0}\r\nK00e9=DST offset\\: {0}\r\nK00ea=era\\: {0}\r\nK00eb={0} failed verification of {1}\r\nK00ec={0} has invalid digest for {1} in {2}\r\nK00ed={0} is not an interface\r\nK00ee={0} is not visible from class loader\r\nK00ef={0} appears more than once\r\nK00f0=non-public interfaces must be in the same package\r\nK00f1=not a proxy instance\r\nK00f2=the methods named {0} must have the same return type\r\nK00f3=Timer was cancelled\r\nK00f5=Illegal delay to start the TimerTask\r\nK00f6=TimerTask is scheduled already\r\nK00f7=TimerTask is cancelled\r\nK00f8=day of week in month\\: {0}\r\nK00f9=min or max digit count too large\r\nK00fa=min digits greater than max digits\r\nK00fb=min or max digits negative\r\nK00fc=Jar entry not specified\r\nK00fd=Invalid keystore\r\nK00fe=Incorrect password\r\nK0185=The alias already exists for a key entry.\r\nK018f=Can\'t convert to BMPString \\: {0}\r\nK0190=No data to decode\r\nK0191=Invalid size, must be a multiple of 64 from 512 to 1024\r\nK0193=An identity with this name already exists in this scope\r\nK0194=An identity in the scope has the same public key\r\nK0195=The existing public key and the one contained in the certificate do not match.\r\nK0196=Certificate is missing\r\nK0199=Count out of range\r\nK01a0=End of stream condition\r\nK01a4=Already shutting down\r\nK01a5=Illegal shutdown hook\\: {0}\r\nK01a6=Invalid filter\r\nK01a7=Name too long: {0}\r\nK01b3=Incorrect number of arguments\r\nK01b4=Cannot convert {0} to {1}\r\nK01b6=Cannot find \\!/\r\nK01c1=File is a Directory\r\nK01c2=Cannot create\\: {0}\r\nK01c3=Unable to open\\: {0}\r\nK01c4=Invalid zip file\\: {0}\r\nK01c6=No Main-Class specified in manifest\\: {0}\r\nK01d1=Signers of \'{0}\' do not match signers of other classes in package\r\nK01d2={1} - protected system package \'{0}\'\r\nK01ec=key size must be a multiple of 8 bits\r\nK01ed=key size must be at least 512 bits\r\nK01fe=Incomplete % sequence at\\: {0}\r\nK01ff=Invalid % sequence ({0}) at\\: {1}\r\nK0220=UTFDataFormatException\r\nK0222=No Manifest found in jar file\\: {0}\r\nK0300=Unsupported encoding\r\nK0301=Not signed data\r\nK0302=Relative path\r\nK0303=Scheme-specific part expected\r\nK0304=Authority expected\r\nK0305=Illegal character in scheme\r\nK0306={0} in schemeSpecificPart\r\nK0307={0} in authority\r\nK0308={0} in path\r\nK0309={0} in query\r\nK030a={0} in fragment\r\nK030c=Expected host\r\nK030d=Illegal character in userinfo\r\nK030e=Expected a closing square bracket for ipv6 address\r\nK030f=Malformed ipv6 address\r\nK0310=Illegal character in host name\r\nK0311=Malformed ipv4 address\r\nK0312=URI is not absolute\r\nK0313=Incomplete % sequence\r\nK0314=Invalid % sequence ({0})\r\nK0315=Socket is already bound\r\nK0316=SocketAddress {0} not supported\r\nK0317=Host is unresolved\\: {0}\r\nK0318=SocketAddress is null\r\nK0319=Exception in thread \"{0}\"\\ \r\nK031a=URI is not absolute\\: {0}\r\nK031b=URI is not hierarchical\\: {0}\r\nK031c=Expected file scheme in URI\\: {0}\r\nK031d=Expected non-empty path in URI\\: {0}\r\nK031e=Found {0} component in URI\\: {1}\r\nK031f=Socket is not bound\r\nK0320=Socket is not connected\r\nK0321=Socket input is shutdown\r\nK0322=Not a supported ISO 4217 Currency Code\\: {0}\r\nK0323=Not a supported ISO 3166 Country locale\\: {0}\r\nK0324=Needs dictionary\r\nK0325=Port out of range\\: {0}\r\nK0326={0} at index {1}\\: {2}\r\nK0327={0}\\: {1}\r\nK0328=Certificate not yet valid\r\nK0329=Certificate expired\r\nK0330=interface name is null\r\nK0331=address is null\r\nK0332=Invalid IP Address is neither 4 or 16 bytes\\: {0}\r\nK0333=Urgent data not supported\r\nK0334=Cannot set network interface with null\r\nK0335=No addresses associated with Interface\r\nK0337=null type not allowed\r\nK0338=Address not associated with an interface - not set\r\nK0339=Invalid IP Address is neither 4 or 16 bytes\r\nK0340={0} incompatible with {1}\r\nK0342=Scheme expected\r\nK0344=Not a valid {0}, subclass should override readResolve()\r\nK0346=Unmatched braces in the pattern\r\nK0347=seek position is negative\r\nK0348=Format specifier \'{0}\'\r\nK0349=Conversion is \'{0}\'\r\nK034a=The flags are {0}\r\nK034b=url and proxy can not be null\r\nK034c=proxy should not be null\r\nK034d=method has not been implemented yet\r\nK034e=Build rules empty\r\nK0351=format is null\r\nKA000=Line too long\r\nKA001=Argument must not be null\r\nKA002=Unshared read of back reference\r\nKA003=different mode already set\r\nKA004=Enums may not be cloned\r\nKA005={0} is not an enum type\r\nKA006={0} is not a constant in the enum type {1}\r\nKA007=field is null\r\nKA008={0} is an illegal radix\r\nKA009=CharsetName is illegal\r\nKA00a=File is null\r\nKA00b=InputStream is null\r\nKA00c=Readable is null\r\nKA00d=ReadableByteChannel is null\r\nKA00e=Radix {0} is less than Character.MIN_RADIX or greater than Character.MAX_RADIX\r\nKA00f=Socket output is shutdown\r\nKA010=Cannot read back reference to unshared object\r\nKA011=Malformed reply from SOCKS server\r\nKA012=No such file or directory\r\nKA013=Number of bytes to skip cannot be negative\r\nKA014=Invalit UUID string\r\nKA015=Incompatible class (base name)\\: {0} but expected {1}\r\n\r\n"; + + // ResourceBundle holding the system messages. +// static private ResourceBundle bundle = null; + +// /** +// * @j2sIgnore +// */ +// static { +// // Attempt to load the messages. +// try { +// bundle = MsgHelp.setLocale(Locale.getDefault(), +// "org.apache.harmony.luni.util.ExternalMessages"); +// } catch (Throwable e) { +// e.printStackTrace(); +// } +// } + + /** + * Retrieves a message which has no arguments. + * + * @param msg + * String the key to look up. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg) { + return getMsg(msg); +// if (bundle == null) +// return msg; +// try { +// return bundle.getString(msg); +// } catch (MissingResourceException e) { +// return msg; +// } + } + + /** + * Retrieves a message which takes 1 argument. + * + * @param msg + * String the key to look up. + * @param arg + * Object the object to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, Object arg) { + return getString(msg, new Object[] { arg }); + } + + /** + * Retrieves a message which takes 1 integer argument. + * + * @param msg + * String the key to look up. + * @param arg + * int the integer to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, int arg) { + return getString(msg, new Object[] { Integer.toString(arg) }); + } + + /** + * Retrieves a message which takes 1 character argument. + * + * @param msg + * String the key to look up. + * @param arg + * char the character to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, char arg) { + return getString(msg, new Object[] { String.valueOf(arg) }); + } + + /** + * Retrieves a message which takes 2 arguments. + * + * @param msg + * String the key to look up. + * @param arg1 + * Object an object to insert in the formatted output. + * @param arg2 + * Object another object to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, Object arg1, Object arg2) { + return getString(msg, new Object[] { arg1, arg2 }); + } + + /** + * Retrieves a message which takes several arguments. + * + * @param msg + * String the key to look up. + * @param args + * Object[] the objects to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, Object[] args) { + String format = getMsg(msg); +// +// +// if (bundle != null) { +// try { +// format = bundle.getString(msg); +// } catch (MissingResourceException e) { +// } +// } +// + return format(format, args); + } + + /** + * SwingJS minimal support for harmony error messages + * + * @param msg + * @return + */ + private static String getMsg(String msg) { + int pt = msgs.indexOf(msg); + return (pt < 0 ? msg : msg.substring(pt + 6, msg.indexOf("\r", pt))); + } + + // from MsgHelp.java + + /** + * Generates a formatted text string given a source string containing + * "argument markers" of the form "{argNum}" where each argNum must be in + * the range 0..9. The result is generated by inserting the toString of each + * argument into the position indicated in the string. + *

+ * To insert the "{" character into the output, use a single backslash + * character to escape it (i.e. "\{"). The "}" character does not need to be + * escaped. + * + * @param format + * String the format to use when printing. + * @param args + * Object[] the arguments to use. + * @return String the formatted message. + */ + public static String format(String format, Object[] args) { + StringBuilder answer = new StringBuilder(format.length() + + (args.length * 20)); + String[] argStrings = new String[args.length]; + for (int i = 0; i < args.length; ++i) { + if (args[i] == null) + argStrings[i] = ""; + else + argStrings[i] = args[i].toString(); + } + int lastI = 0; + for (int i = format.indexOf('{', 0); i >= 0; i = format.indexOf('{', + lastI)) { + if (i != 0 && format.charAt(i - 1) == '\\') { + // It's escaped, just print and loop. + if (i != 1) + answer.append(format.substring(lastI, i - 1)); + answer.append('{'); + lastI = i + 1; + } else { + // It's a format character. + if (i > format.length() - 3) { + // Bad format, just print and loop. + answer.append(format.substring(lastI, format.length())); + lastI = format.length(); + } else { +// int argnum = (byte) Character.digit(format.charAt(i + 1), +// 10); + int argnum = (byte) (format.charAt(i + 1) - '0'); + if (argnum < 0 || format.charAt(i + 2) != '}') { + // Bad format, just print and loop. + answer.append(format.substring(lastI, i + 1)); + lastI = i + 1; + } else { + // Got a good one! + answer.append(format.substring(lastI, i)); + if (argnum >= argStrings.length) + answer.append(""); + else + answer.append(argStrings[argnum]); + lastI = i + 3; + } + } + } + } + if (lastI < format.length()) + answer.append(format.substring(lastI, format.length())); + return answer.toString(); + } + +} diff --git a/src/org/apache/harmony/luni/util/MsgHelp.java b/src/org/apache/harmony/luni/util/MsgHelp.java new file mode 100644 index 0000000..592d8b3 --- /dev/null +++ b/src/org/apache/harmony/luni/util/MsgHelp.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.util; + +/** + * This class contains helper methods for loading resource bundles and + * formatting external message strings. + * + */ + +public final class MsgHelp { + + /** + * Generates a formatted text string given a source string containing + * "argument markers" of the form "{argNum}" where each argNum must be in + * the range 0..9. The result is generated by inserting the toString of each + * argument into the position indicated in the string. + *

+ * To insert the "{" character into the output, use a single backslash + * character to escape it (i.e. "\{"). The "}" character does not need to be + * escaped. + * + * @param format + * String the format to use when printing. + * @param args + * Object[] the arguments to use. + * @return String the formatted message. + */ + public static String format(String format, Object[] args) { + StringBuilder answer = new StringBuilder(format.length() + + (args.length * 20)); + String[] argStrings = new String[args.length]; + for (int i = 0; i < args.length; ++i) { + if (args[i] == null) + argStrings[i] = ""; + else + argStrings[i] = args[i].toString(); + } + int lastI = 0; + for (int i = format.indexOf('{', 0); i >= 0; i = format.indexOf('{', + lastI)) { + if (i != 0 && format.charAt(i - 1) == '\\') { + // It's escaped, just print and loop. + if (i != 1) + answer.append(format.substring(lastI, i - 1)); + answer.append('{'); + lastI = i + 1; + } else { + // It's a format character. + if (i > format.length() - 3) { + // Bad format, just print and loop. + answer.append(format.substring(lastI, format.length())); + lastI = format.length(); + } else { +// int argnum = (byte) Character.digit(format.charAt(i + 1), +// 10); + int argnum = (byte) (format.charAt(i + 1) - '0'); + if (argnum < 0 || format.charAt(i + 2) != '}') { + // Bad format, just print and loop. + answer.append(format.substring(lastI, i + 1)); + lastI = i + 1; + } else { + // Got a good one! + answer.append(format.substring(lastI, i)); + if (argnum >= argStrings.length) + answer.append(""); + else + answer.append(argStrings[argnum]); + lastI = i + 3; + } + } + } + } + if (lastI < format.length()) + answer.append(format.substring(lastI, format.length())); + return answer.toString(); + } + +// /** +// * Changes the locale of the messages. +// * +// * @param locale +// * Locale the locale to change to. +// */ +// static public ResourceBundle setLocale(final Locale locale, +// final String resource) { +// /* +// try { +// final ClassLoader loader = VM.bootCallerClassLoader(); +// return (ResourceBundle) AccessController +// .doPrivileged(new PrivilegedAction() { +// public Object run() { +// return ResourceBundle.getBundle(resource, locale, +// loader != null ? loader : ClassLoader.getSystemClassLoader()); +// } +// }); +// } catch (MissingResourceException e) { +// } +// */ +// /** +// * @j2sNative +// * +// * Class.forName("java.util.ResourceBundle"); +// */ +// {} +// return ResourceBundle.getBundle(resource); +// //return null; +// } +} diff --git a/src/org/apache/tools/bzip2/BZip2Constants.java b/src/org/apache/tools/bzip2/BZip2Constants.java new file mode 100644 index 0000000..3a511a7 --- /dev/null +++ b/src/org/apache/tools/bzip2/BZip2Constants.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* + * This package is based on the work done by Keiron Liddle, Aftex Software + * to whom the Ant project is very grateful for his + * great code. + */ + +package org.apache.tools.bzip2; + +/** + * Base class for both the compress and decompress classes. + * Holds common arrays, and static data. + *

+ * This interface is public for historical purposes. + * You should have no need to use it. + *

+ */ +public interface BZip2Constants { + + int baseBlockSize = 100000; + int MAX_ALPHA_SIZE = 258; + int MAX_CODE_LEN = 23; + int RUNA = 0; + int RUNB = 1; + int N_GROUPS = 6; + int G_SIZE = 50; + int N_ITERS = 4; + int MAX_SELECTORS = (2 + (900000 / G_SIZE)); + int NUM_OVERSHOOT_BYTES = 20; + + /** + * This array really shouldn't be here. + * Again, for historical purposes it is. + * + *

FIXME: This array should be in a private or package private + * location, since it could be modified by malicious code.

+ */ + int[] rNums = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 + }; +} diff --git a/src/org/apache/tools/bzip2/CBZip2InputStream.java b/src/org/apache/tools/bzip2/CBZip2InputStream.java new file mode 100644 index 0000000..fc25a31 --- /dev/null +++ b/src/org/apache/tools/bzip2/CBZip2InputStream.java @@ -0,0 +1,1063 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* + * This package is based on the work done by Keiron Liddle, Aftex Software + * to whom the Ant project is very grateful for his + * great code. + */ +package org.apache.tools.bzip2; + +import java.io.IOException; +import java.io.InputStream; + +/** + * An input stream that decompresses from the BZip2 format (without the file + * header chars) to be read as any other stream. + * + *

The decompression requires large amounts of memory. Thus you + * should call the {@link #close() close()} method as soon as + * possible, to force CBZip2InputStream to release the + * allocated memory. See {@link CBZip2OutputStream + * CBZip2OutputStream} for information about memory usage.

+ * + *

CBZip2InputStream reads bytes from the compressed + * source stream via the single byte {@link java.io.InputStream#read() + * read()} method exclusively. Thus you should consider to use a + * buffered source stream.

+ * + *

Instances of this class are not threadsafe.

+ */ +public class CBZip2InputStream extends InputStream implements BZip2Constants { + + /** + * Index of the last char in the block, so the block size == last + 1. + */ + private int last; + + /** + * Index in zptr[] of original string after sorting. + */ + private int origPtr; + + /** + * always: in the range 0 .. 9. + * The current block size is 100000 * this number. + */ + private int blockSize100k; + + private boolean blockRandomised; + + private int bsBuff; + private int bsLive; + private final CRC crc = new CRC(); + + private int nInUse; + + private InputStream in; + private final boolean decompressConcatenated; + + private int currentChar = -1; + + private static final int EOF = 0; + private static final int START_BLOCK_STATE = 1; + private static final int RAND_PART_A_STATE = 2; + private static final int RAND_PART_B_STATE = 3; + private static final int RAND_PART_C_STATE = 4; + private static final int NO_RAND_PART_A_STATE = 5; + private static final int NO_RAND_PART_B_STATE = 6; + private static final int NO_RAND_PART_C_STATE = 7; + + private int currentState = START_BLOCK_STATE; + + private int storedBlockCRC, storedCombinedCRC; + private int computedBlockCRC, computedCombinedCRC; + + // Variables used by setup* methods exclusively + + private int su_count; + private int su_ch2; + private int su_chPrev; + private int su_i2; + private int su_j2; + private int su_rNToGo; + private int su_rTPos; + private int su_tPos; + private char su_z; + + /** + * All memory intensive stuff. + * This field is initialized by initBlock(). + */ + private CBZip2InputStream.Data data; + + /** + * Constructs a new CBZip2InputStream which decompresses bytes read from + * the specified stream. This doesn't suppprt decompressing + * concatenated .bz2 files. + * + *

Although BZip2 headers are marked with the magic + * "Bz" this constructor expects the next byte in the + * stream to be the first one after the magic. Thus callers have + * to skip the first two bytes. Otherwise this constructor will + * throw an exception.

+ * @param in + * + * @throws IOException + * if the stream content is malformed or an I/O error occurs. + * @throws NullPointerException + * if in == null + */ + public CBZip2InputStream(final InputStream in) throws IOException { + this(in, false); + } + + /** + * Constructs a new CBZip2InputStream which decompresses bytes + * read from the specified stream. + * + *

Although BZip2 headers are marked with the magic + * "Bz" this constructor expects the next byte in the + * stream to be the first one after the magic. Thus callers have + * to skip the first two bytes. Otherwise this constructor will + * throw an exception.

+ * + * @param in the InputStream from which this object should be created + * @param decompressConcatenated + * if true, decompress until the end of the input; + * if false, stop after the first .bz2 stream and + * leave the input position to point to the next + * byte after the .bz2 stream + * + * @throws IOException + * if the stream content is malformed or an I/O error occurs. + * @throws NullPointerException + * if in == null + */ + public CBZip2InputStream(final InputStream in, + final boolean decompressConcatenated) + throws IOException { + super(); + + this.in = in; + this.decompressConcatenated = decompressConcatenated; + + init(true); + initBlock(); + setupBlock(); + } + + /** {@inheritDoc} */ + @Override + public int read() throws IOException { + if (this.in == null) + throw new IOException("stream closed"); + return read0(); + } + + /* + * (non-Javadoc) + * + * @see java.io.InputStream#read(byte[], int, int) + */ + @Override + public int read(final byte[] dest, final int offs, final int len) + throws IOException { + if (offs < 0) { + throw new IndexOutOfBoundsException("offs(" + offs + ") < 0."); + } + if (len < 0) { + throw new IndexOutOfBoundsException("len(" + len + ") < 0."); + } + if (offs + len > dest.length) { + throw new IndexOutOfBoundsException("offs(" + offs + ") + len(" + + len + ") > dest.length(" + + dest.length + ")."); + } + if (this.in == null) { + throw new IOException("stream closed"); + } + + final int hi = offs + len; + int destOffs = offs; + for (int b; (destOffs < hi) && ((b = read0()) >= 0);) { + dest[destOffs++] = (byte) b; + } + + return (destOffs == offs) ? -1 : (destOffs - offs); + } + + private void makeMaps() { + final boolean[] inUse = this.data.inUse; + final byte[] seqToUnseq = this.data.seqToUnseq; + + int nInUseShadow = 0; + + for (int i = 0; i < 256; i++) { + if (inUse[i]) { + seqToUnseq[nInUseShadow++] = (byte) i; + } + } + + this.nInUse = nInUseShadow; + } + + private int read0() throws IOException { + final int retChar = this.currentChar; + + switch (this.currentState) { + case EOF: + return -1; + + case START_BLOCK_STATE: + throw new IllegalStateException(); + + case RAND_PART_A_STATE: + throw new IllegalStateException(); + + case RAND_PART_B_STATE: + setupRandPartB(); + break; + + case RAND_PART_C_STATE: + setupRandPartC(); + break; + + case NO_RAND_PART_A_STATE: + throw new IllegalStateException(); + + case NO_RAND_PART_B_STATE: + setupNoRandPartB(); + break; + + case NO_RAND_PART_C_STATE: + setupNoRandPartC(); + break; + + default: + throw new IllegalStateException(); + } + + return retChar; + } + + private boolean init(boolean isFirstStream) throws IOException { + if (null == in) { + throw new IOException("No InputStream"); + } + + if (isFirstStream) { + if (in.available() == 0) { + throw new IOException("Empty InputStream"); + } + } else { + int magic0 = read(); + if (magic0 == -1) { + return false; + } + int magic1 = read(); + if (magic0 != 'B' || magic1 != 'Z') { + throw new IOException("Garbage after a valid BZip2 stream"); + } + } + + int magic2 = read(); + if (magic2 != 'h') { + throw new IOException(isFirstStream + ? "Stream is not in the BZip2 format" + : "Garbage after a valid BZip2 stream"); + } + + int blockSize = read(); + if ((blockSize < '1') || (blockSize > '9')) { + throw new IOException("Stream is not BZip2 formatted: illegal " + + "blocksize " + (char) blockSize); + } + + this.blockSize100k = blockSize - '0'; + + this.bsLive = 0; + this.computedCombinedCRC = 0; + + return true; + } + + private void initBlock() throws IOException { + char magic0; + char magic1; + char magic2; + char magic3; + char magic4; + char magic5; + + while (true) { + // Get the block magic bytes. + magic0 = bsGetUByte(); + magic1 = bsGetUByte(); + magic2 = bsGetUByte(); + magic3 = bsGetUByte(); + magic4 = bsGetUByte(); + magic5 = bsGetUByte(); + + // If isn't end of stream magic, break out of the loop. + if (magic0 != 0x17 || magic1 != 0x72 || magic2 != 0x45 || magic3 != 0x38 + || magic4 != 0x50 || magic5 != 0x90) { + break; + } + + // End of stream was reached. Check the combined CRC and + // advance to the next .bz2 stream if decoding concatenated + // streams. + if (complete()) { + return; + } + } + + if (magic0 != 0x31 || // '1' + magic1 != 0x41 || // ')' + magic2 != 0x59 || // 'Y' + magic3 != 0x26 || // '&' + magic4 != 0x53 || // 'S' + magic5 != 0x59 // 'Y' + ) { + this.currentState = EOF; + throw new IOException("bad block header"); + } + this.storedBlockCRC = bsGetInt(); + this.blockRandomised = bsR(1) == 1; + + /** + * Allocate data here instead in constructor, so we do not allocate it if + * the input file is empty. + */ + if (this.data == null) { + this.data = new Data(this.blockSize100k); + } + + // currBlockNo++; + getAndMoveToFrontDecode(); + + this.crc.initialiseCRC(); + this.currentState = START_BLOCK_STATE; + } + + private void endBlock() throws IOException { + this.computedBlockCRC = this.crc.getFinalCRC(); + + // A bad CRC is considered a fatal error. + if (this.storedBlockCRC != this.computedBlockCRC) { + // make next blocks readable without error + // (repair feature, not yet documented, not tested) + this.computedCombinedCRC + = (this.storedCombinedCRC << 1) + | (this.storedCombinedCRC >>> 31); + this.computedCombinedCRC ^= this.storedBlockCRC; + + reportCRCError(); + } + + this.computedCombinedCRC + = (this.computedCombinedCRC << 1) + | (this.computedCombinedCRC >>> 31); + this.computedCombinedCRC ^= this.computedBlockCRC; + } + + private boolean complete() throws IOException { + this.storedCombinedCRC = bsGetInt(); + this.currentState = EOF; + this.data = null; + + if (this.storedCombinedCRC != this.computedCombinedCRC) { + reportCRCError(); + } + + // Look for the next .bz2 stream if decompressing + // concatenated files. + return !decompressConcatenated || !init(false); + } + + @Override + public void close() throws IOException { + InputStream inShadow = this.in; + if (inShadow != null) { + try { + if (inShadow != System.in) { + inShadow.close(); + } + } finally { + this.data = null; + this.in = null; + } + } + } + + private int bsR(final int n) throws IOException { + int bsLiveShadow = this.bsLive; + int bsBuffShadow = this.bsBuff; + + if (bsLiveShadow < n) { + final InputStream inShadow = this.in; + do { + int thech = read();//inShadow.read(); + + if (thech < 0) { + throw new IOException("unexpected end of stream"); + } + + bsBuffShadow = (bsBuffShadow << 8) | thech; + bsLiveShadow += 8; + } while (bsLiveShadow < n); + + this.bsBuff = bsBuffShadow; + } + + this.bsLive = bsLiveShadow - n; + return (bsBuffShadow >> (bsLiveShadow - n)) & ((1 << n) - 1); + } + + private boolean bsGetBit() throws IOException { + int bsLiveShadow = this.bsLive; + int bsBuffShadow = this.bsBuff; + + if (bsLiveShadow < 1) { + int thech = read(); + + if (thech < 0) { + throw new IOException("unexpected end of stream"); + } + + bsBuffShadow = (bsBuffShadow << 8) | thech; + bsLiveShadow += 8; + this.bsBuff = bsBuffShadow; + } + + this.bsLive = bsLiveShadow - 1; + return ((bsBuffShadow >> (bsLiveShadow - 1)) & 1) != 0; + } + + private char bsGetUByte() throws IOException { + return (char) bsR(8); + } + + private int bsGetInt() throws IOException { + return (((((bsR(8) << 8) | bsR(8)) << 8) | bsR(8)) << 8) | bsR(8); + } + + /** + * Called by createHuffmanDecodingTables() exclusively. + * @param limit + * @param base + * @param perm + * @param length + * @param minLen + * @param maxLen + * @param alphaSize + */ + private static void hbCreateDecodeTables(final int[] limit, + final int[] base, + final int[] perm, + final char[] length, + final int minLen, + final int maxLen, + final int alphaSize) { + for (int i = minLen, pp = 0; i <= maxLen; i++) { + for (int j = 0; j < alphaSize; j++) { + if (length[j] == i) { + perm[pp++] = j; + } + } + } + + for (int i = MAX_CODE_LEN; --i > 0;) { + base[i] = 0; + limit[i] = 0; + } + + for (int i = 0; i < alphaSize; i++) { + base[length[i] + 1]++; + } + + for (int i = 1, b = base[0]; i < MAX_CODE_LEN; i++) { + b += base[i]; + base[i] = b; + } + + for (int i = minLen, vec = 0, b = base[i]; i <= maxLen; i++) { + final int nb = base[i + 1]; + vec += nb - b; + b = nb; + limit[i] = vec - 1; + vec <<= 1; + } + + for (int i = minLen + 1; i <= maxLen; i++) { + base[i] = ((limit[i - 1] + 1) << 1) - base[i]; + } + } + + private void recvDecodingTables() throws IOException { + final Data dataShadow = this.data; + final boolean[] inUse = dataShadow.inUse; + final byte[] pos = dataShadow.recvDecodingTables_pos; + final byte[] selector = dataShadow.selector; + final byte[] selectorMtf = dataShadow.selectorMtf; + + int inUse16 = 0; + + /* Receive the mapping table */ + for (int i = 0; i < 16; i++) { + if (bsGetBit()) { + inUse16 |= 1 << i; + } + } + + for (int i = 256; --i >= 0;) { + inUse[i] = false; + } + + for (int i = 0; i < 16; i++) { + if ((inUse16 & (1 << i)) != 0) { + final int i16 = i << 4; + for (int j = 0; j < 16; j++) { + if (bsGetBit()) { + inUse[i16 + j] = true; + } + } + } + } + + makeMaps(); + final int alphaSize = this.nInUse + 2; + + /* Now the selectors */ + final int nGroups = bsR(3); + final int nSelectors = bsR(15); + + for (int i = 0; i < nSelectors; i++) { + int j = 0; + while (bsGetBit()) { + j++; + } + selectorMtf[i] = (byte) j; + } + + /* Undo the MTF values for the selectors. */ + for (int v = nGroups; --v >= 0;) { + pos[v] = (byte) v; + } + + for (int i = 0; i < nSelectors; i++) { + int v = selectorMtf[i] & 0xff; + final byte tmp = pos[v]; + while (v > 0) { + // nearly all times v is zero, 4 in most other cases + pos[v] = pos[v - 1]; + v--; + } + pos[0] = tmp; + selector[i] = tmp; + } + + final char[][] len = dataShadow.temp_charArray2d; + + /* Now the coding tables */ + for (int t = 0; t < nGroups; t++) { + int curr = bsR(5); + final char[] len_t = len[t]; + for (int i = 0; i < alphaSize; i++) { + while (bsGetBit()) { + curr += bsGetBit() ? -1 : 1; + } + len_t[i] = (char) curr; + } + } + + // finally create the Huffman tables + createHuffmanDecodingTables(alphaSize, nGroups); + } + + /** + * Called by recvDecodingTables() exclusively. + * @param alphaSize + * @param nGroups + */ + private void createHuffmanDecodingTables(final int alphaSize, + final int nGroups) { + final Data dataShadow = this.data; + final char[][] len = dataShadow.temp_charArray2d; + final int[] minLens = dataShadow.minLens; + final int[][] limit = dataShadow.limit; + final int[][] base = dataShadow.base; + final int[][] perm = dataShadow.perm; + + for (int t = 0; t < nGroups; t++) { + int minLen = 32; + int maxLen = 0; + final char[] len_t = len[t]; + for (int i = alphaSize; --i >= 0;) { + final char lent = len_t[i]; + if (lent > maxLen) { + maxLen = lent; + } + if (lent < minLen) { + minLen = lent; + } + } + hbCreateDecodeTables(limit[t], base[t], perm[t], len[t], minLen, + maxLen, alphaSize); + minLens[t] = minLen; + } + } + + private void getAndMoveToFrontDecode() throws IOException { + this.origPtr = bsR(24); + recvDecodingTables(); + + final InputStream inShadow = this.in; + final Data dataShadow = this.data; + final byte[] ll8 = dataShadow.ll8; + final int[] unzftab = dataShadow.unzftab; + final byte[] selector = dataShadow.selector; + final byte[] seqToUnseq = dataShadow.seqToUnseq; + final char[] yy = dataShadow.getAndMoveToFrontDecode_yy; + final int[] minLens = dataShadow.minLens; + final int[][] limit = dataShadow.limit; + final int[][] base = dataShadow.base; + final int[][] perm = dataShadow.perm; + final int limitLast = this.blockSize100k * 100000; + + /* + Setting up the unzftab entries here is not strictly + necessary, but it does save having to do it later + in a separate pass, and so saves a block's worth of + cache misses. + */ + for (int i = 256; --i >= 0;) { + yy[i] = (char) i; + unzftab[i] = 0; + } + + int groupNo = 0; + int groupPos = G_SIZE - 1; + final int eob = this.nInUse + 1; + int nextSym = getAndMoveToFrontDecode0(0); + int bsBuffShadow = this.bsBuff; + int bsLiveShadow = this.bsLive; + int lastShadow = -1; + int zt = selector[groupNo] & 0xff; + int[] base_zt = base[zt]; + int[] limit_zt = limit[zt]; + int[] perm_zt = perm[zt]; + int minLens_zt = minLens[zt]; + + while (nextSym != eob) { + if ((nextSym == RUNA) || (nextSym == RUNB)) { + int s = -1; + + for (int n = 1; true; n <<= 1) { + if (nextSym == RUNA) { + s += n; + } else if (nextSym == RUNB) { + s += n << 1; + } else { + break; + } + + if (groupPos == 0) { + groupPos = G_SIZE - 1; + zt = selector[++groupNo] & 0xff; + base_zt = base[zt]; + limit_zt = limit[zt]; + perm_zt = perm[zt]; + minLens_zt = minLens[zt]; + } else { + groupPos--; + } + + int zn = minLens_zt; + + // Inlined: + // int zvec = bsR(zn); + while (bsLiveShadow < zn) { + final int thech = read();//inShadow.read(); + if (thech < 0) + throw new IOException("unexpected end of stream"); + + bsBuffShadow = (bsBuffShadow << 8) | thech; + bsLiveShadow += 8; + continue; + } + int zvec = (bsBuffShadow >> (bsLiveShadow - zn)) & ((1 << zn) - 1); + bsLiveShadow -= zn; + + while (zvec > limit_zt[zn]) { + zn++; + while (bsLiveShadow < 1) { + final int thech = read();//inShadow.read(); + if (thech < 0) + throw new IOException("unexpected end of stream"); + bsBuffShadow = (bsBuffShadow << 8) | thech; + bsLiveShadow += 8; + continue; + } + bsLiveShadow--; + zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1); + } + nextSym = perm_zt[zvec - base_zt[zn]]; + } + + final byte ch = seqToUnseq[yy[0]]; + unzftab[ch & 0xff] += s + 1; + + while (s-- >= 0) { + ll8[++lastShadow] = ch; + } + + if (lastShadow >= limitLast) { + throw new IOException("block overrun"); + } + } else { + if (++lastShadow >= limitLast) { + throw new IOException("block overrun"); + } + + final char tmp = yy[nextSym - 1]; + unzftab[seqToUnseq[tmp] & 0xff]++; + ll8[lastShadow] = seqToUnseq[tmp]; + + /* + This loop is hammered during decompression, + hence avoid native method call overhead of + System.arraycopy for very small ranges to copy. + */ + if (nextSym <= 16) { + for (int j = nextSym - 1; j > 0;) { + yy[j] = yy[--j]; + } + } else { + System.arraycopy(yy, 0, yy, 1, nextSym - 1); + } + + yy[0] = tmp; + + if (groupPos == 0) { + groupPos = G_SIZE - 1; + zt = selector[++groupNo] & 0xff; + base_zt = base[zt]; + limit_zt = limit[zt]; + perm_zt = perm[zt]; + minLens_zt = minLens[zt]; + } else { + groupPos--; + } + + int zn = minLens_zt; + + // Inlined: + // int zvec = bsR(zn); + while (bsLiveShadow < zn) { + final int thech = read();//inShadow.read(); + if (thech < 0) + throw new IOException("unexpected end of stream"); + bsBuffShadow = (bsBuffShadow << 8) | thech; + bsLiveShadow += 8; + continue; + } + int zvec = (bsBuffShadow >> (bsLiveShadow - zn)) & ((1 << zn) - 1); + bsLiveShadow -= zn; + + while (zvec > limit_zt[zn]) { + zn++; + while (bsLiveShadow < 1) { + final int thech = read();//inShadow.read(); + if (thech <0) + throw new IOException("unexpected end of stream"); + bsBuffShadow = (bsBuffShadow << 8) | thech; + bsLiveShadow += 8; + continue; + } + bsLiveShadow--; + zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1); + } + nextSym = perm_zt[zvec - base_zt[zn]]; + } + } + + this.last = lastShadow; + this.bsLive = bsLiveShadow; + this.bsBuff = bsBuffShadow; + } + + private int getAndMoveToFrontDecode0(final int groupNo) throws IOException { + final InputStream inShadow = this.in; + final Data dataShadow = this.data; + final int zt = dataShadow.selector[groupNo] & 0xff; + final int[] limit_zt = dataShadow.limit[zt]; + int zn = dataShadow.minLens[zt]; + int zvec = bsR(zn); + int bsLiveShadow = this.bsLive; + int bsBuffShadow = this.bsBuff; + + while (zvec > limit_zt[zn]) { + zn++; + while (bsLiveShadow < 1) { + final int thech = read();//inShadow.read(); + + if (thech < 0) + throw new IOException("unexpected end of stream"); + + bsBuffShadow = (bsBuffShadow << 8) | thech; + bsLiveShadow += 8; + continue; + } + bsLiveShadow--; + zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1); + } + + this.bsLive = bsLiveShadow; + this.bsBuff = bsBuffShadow; + + return dataShadow.perm[zt][zvec - dataShadow.base[zt][zn]]; + } + + private void setupBlock() throws IOException { + if (this.data == null) { + return; + } + + final int[] cftab = this.data.cftab; + final int[] tt = this.data.initTT(this.last + 1); + final byte[] ll8 = this.data.ll8; + cftab[0] = 0; + System.arraycopy(this.data.unzftab, 0, cftab, 1, 256); + + for (int i = 1, c = cftab[0]; i <= 256; i++) { + c += cftab[i]; + cftab[i] = c; + } + + for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) { + tt[cftab[ll8[i] & 0xff]++] = i; + } + + if ((this.origPtr < 0) || (this.origPtr >= tt.length)) { + throw new IOException("stream corrupted"); + } + + this.su_tPos = tt[this.origPtr]; + this.su_count = 0; + this.su_i2 = 0; + this.su_ch2 = 256; /* not a char and not EOF */ + + if (this.blockRandomised) { + this.su_rNToGo = 0; + this.su_rTPos = 0; + setupRandPartA(); + } else { + setupNoRandPartA(); + } + } + + private void setupRandPartA() throws IOException { + if (this.su_i2 <= this.last) { + this.su_chPrev = this.su_ch2; + int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff; + this.su_tPos = this.data.tt[this.su_tPos]; + if (this.su_rNToGo == 0) { + this.su_rNToGo = BZip2Constants.rNums[this.su_rTPos] - 1; + if (++this.su_rTPos == 512) { + this.su_rTPos = 0; + } + } else { + this.su_rNToGo--; + } + this.su_ch2 = su_ch2Shadow ^= (this.su_rNToGo == 1) ? 1 : 0; + this.su_i2++; + this.currentChar = su_ch2Shadow; + this.currentState = RAND_PART_B_STATE; + this.crc.updateCRC(su_ch2Shadow); + } else { + endBlock(); + initBlock(); + setupBlock(); + } + } + + private void setupNoRandPartA() throws IOException { + if (this.su_i2 <= this.last) { + this.su_chPrev = this.su_ch2; + int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff; + this.su_ch2 = su_ch2Shadow; + this.su_tPos = this.data.tt[this.su_tPos]; + this.su_i2++; + this.currentChar = su_ch2Shadow; + this.currentState = NO_RAND_PART_B_STATE; + this.crc.updateCRC(su_ch2Shadow); + } else { + this.currentState = NO_RAND_PART_A_STATE; + endBlock(); + initBlock(); + setupBlock(); + } + } + + private void setupRandPartB() throws IOException { + if (this.su_ch2 != this.su_chPrev) { + this.currentState = RAND_PART_A_STATE; + this.su_count = 1; + setupRandPartA(); + } else if (++this.su_count >= 4) { + this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff); + this.su_tPos = this.data.tt[this.su_tPos]; + if (this.su_rNToGo == 0) { + this.su_rNToGo = BZip2Constants.rNums[this.su_rTPos] - 1; + if (++this.su_rTPos == 512) { + this.su_rTPos = 0; + } + } else { + this.su_rNToGo--; + } + this.su_j2 = 0; + this.currentState = RAND_PART_C_STATE; + if (this.su_rNToGo == 1) { + this.su_z ^= 1; + } + setupRandPartC(); + } else { + this.currentState = RAND_PART_A_STATE; + setupRandPartA(); + } + } + + private void setupRandPartC() throws IOException { + if (this.su_j2 < this.su_z) { + this.currentChar = this.su_ch2; + this.crc.updateCRC(this.su_ch2); + this.su_j2++; + } else { + this.currentState = RAND_PART_A_STATE; + this.su_i2++; + this.su_count = 0; + setupRandPartA(); + } + } + + private void setupNoRandPartB() throws IOException { + if (this.su_ch2 != this.su_chPrev) { + this.su_count = 1; + setupNoRandPartA(); + } else if (++this.su_count >= 4) { + this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff); + this.su_tPos = this.data.tt[this.su_tPos]; + this.su_j2 = 0; + setupNoRandPartC(); + } else { + setupNoRandPartA(); + } + } + + private void setupNoRandPartC() throws IOException { + if (this.su_j2 < this.su_z) { + int su_ch2Shadow = this.su_ch2; + this.currentChar = su_ch2Shadow; + this.crc.updateCRC(su_ch2Shadow); + this.su_j2++; + this.currentState = NO_RAND_PART_C_STATE; + } else { + this.su_i2++; + this.su_count = 0; + setupNoRandPartA(); + } + } + + private static final class Data extends Object { + + // (with blockSize 900k) + final boolean[] inUse = new boolean[256]; // 256 byte + + final byte[] seqToUnseq = new byte[256]; // 256 byte + final byte[] selector = new byte[MAX_SELECTORS]; // 18002 byte + final byte[] selectorMtf = new byte[MAX_SELECTORS]; // 18002 byte + + /** + * Freq table collected to save a pass over the data during + * decompression. + */ + final int[] unzftab = new int[256]; // 1024 byte + + final int[][] limit = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte + final int[][] base = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte + final int[][] perm = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte + final int[] minLens = new int[N_GROUPS]; // 24 byte + + final int[] cftab = new int[257]; // 1028 byte + final char[] getAndMoveToFrontDecode_yy = new char[256]; // 512 byte + final char[][] temp_charArray2d = new char[N_GROUPS][MAX_ALPHA_SIZE]; // 3096 byte + final byte[] recvDecodingTables_pos = new byte[N_GROUPS]; // 6 byte + //--------------- + // 60798 byte + + int[] tt; // 3600000 byte + byte[] ll8; // 900000 byte + //--------------- + // 4560782 byte + //=============== + + Data(int blockSize100k) { + super(); + + this.ll8 = new byte[blockSize100k * BZip2Constants.baseBlockSize]; + } + + /** + * Initializes the {@link #tt} array. + * + * This method is called when the required length of the array + * is known. I don't initialize it at construction time to + * avoid unnecessary memory allocation when compressing small + * files. + * @param length + * @return int array + */ + final int[] initTT(int length) { + int[] ttShadow = this.tt; + + // tt.length should always be >= length, but theoretically + // it can happen, if the compressor mixed small and large + // blocks. Normally only the last block will be smaller + // than others. + if ((ttShadow == null) || (ttShadow.length < length)) { + this.tt = ttShadow = new int[length]; + } + + return ttShadow; + } + + } + + @SuppressWarnings("unused") + private static void reportCRCError() throws IOException { + // The clean way would be to throw an exception. + //throw new IOException("crc error"); + + // Just print a message, like the previous versions of this class did + System.err.println("BZip2 CRC error"); + } + +} + diff --git a/src/org/apache/tools/bzip2/CBZip2InputStreamFactory.java b/src/org/apache/tools/bzip2/CBZip2InputStreamFactory.java new file mode 100644 index 0000000..23923a3 --- /dev/null +++ b/src/org/apache/tools/bzip2/CBZip2InputStreamFactory.java @@ -0,0 +1,21 @@ +package org.apache.tools.bzip2; + +import java.io.IOException; +import java.io.InputStream; + +public class CBZip2InputStreamFactory { + + /** + * jsjava addition for reflection + * + * @param is + * @return BZip2 input stream + * @throws IOException + */ + public CBZip2InputStream getStream(InputStream is) throws IOException { + is.read(new byte[2], 0, 2); + return new CBZip2InputStream(is); + } + +} + diff --git a/src/org/apache/tools/bzip2/CRC.java b/src/org/apache/tools/bzip2/CRC.java new file mode 100644 index 0000000..0102c8e --- /dev/null +++ b/src/org/apache/tools/bzip2/CRC.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* + * This package is based on the work done by Keiron Liddle, Aftex Software + * to whom the Ant project is very grateful for his + * great code. + */ + +package org.apache.tools.bzip2; + +/** + * A simple class the hold and calculate the CRC for sanity checking + * of the data. + * + */ +final class CRC { + static final int crc32Table[] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, + 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, + 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, + 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, + 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, + 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, + 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, + 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, + 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, + 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, + 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, + 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, + 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, + 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, + 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, + 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, + 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, + 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, + 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, + 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, + 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, + 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 + }; + + CRC() { + initialiseCRC(); + } + + void initialiseCRC() { + globalCrc = 0xffffffff; + } + + int getFinalCRC() { + return ~globalCrc; + } + + int getGlobalCRC() { + return globalCrc; + } + + void setGlobalCRC(int newCrc) { + globalCrc = newCrc; + } + + void updateCRC(int inCh) { + int temp = (globalCrc >> 24) ^ inCh; + if (temp < 0) { + temp = 256 + temp; + } + globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp]; + } + + void updateCRC(int inCh, int repeat) { + int globalCrcShadow = this.globalCrc; + while (repeat-- > 0) { + int temp = (globalCrcShadow >> 24) ^ inCh; + globalCrcShadow = (globalCrcShadow << 8) ^ crc32Table[(temp >= 0) + ? temp + : (temp + 256)]; + } + this.globalCrc = globalCrcShadow; + } + + int globalCrc; +} + diff --git a/src/org/xml/sax/AttributeList.java b/src/org/xml/sax/AttributeList.java new file mode 100644 index 0000000..9285eac --- /dev/null +++ b/src/org/xml/sax/AttributeList.java @@ -0,0 +1,193 @@ +// SAX Attribute List Interface. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: AttributeList.java,v 1.7 2004/04/26 17:34:34 dmegginson Exp $ + +package org.xml.sax; + +/** + * Interface for an element's attribute specifications. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This is the original SAX1 interface for reporting an element's + * attributes. Unlike the new {@link org.xml.sax.Attributes Attributes} + * interface, it does not support Namespace-related information.

+ * + *

When an attribute list is supplied as part of a + * {@link org.xml.sax.DocumentHandler#startElement startElement} + * event, the list will return valid results only during the + * scope of the event; once the event handler returns control + * to the parser, the attribute list is invalid. To save a + * persistent copy of the attribute list, use the SAX1 + * {@link org.xml.sax.helpers.AttributeListImpl AttributeListImpl} + * helper class.

+ * + *

An attribute list includes only attributes that have been + * specified or defaulted: #IMPLIED attributes will not be included.

+ * + *

There are two ways for the SAX application to obtain information + * from the AttributeList. First, it can iterate through the entire + * list:

+ * + *
+ * public void startElement (String name, AttributeList atts) {
+ *   for (int i = 0; i < atts.getLength(); i++) {
+ *     String name = atts.getName(i);
+ *     String type = atts.getType(i);
+ *     String value = atts.getValue(i);
+ *     [...]
+ *   }
+ * }
+ * 
+ * + *

(Note that the result of getLength() will be zero if there + * are no attributes.) + * + *

As an alternative, the application can request the value or + * type of specific attributes:

+ * + *
+ * public void startElement (String name, AttributeList atts) {
+ *   String identifier = atts.getValue("id");
+ *   String label = atts.getValue("label");
+ *   [...]
+ * }
+ * 
+ * + * @deprecated This interface has been replaced by the SAX2 + * {@link org.xml.sax.Attributes Attributes} + * interface, which includes Namespace support. + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.DocumentHandler#startElement startElement + * @see org.xml.sax.helpers.AttributeListImpl AttributeListImpl + */ +public interface AttributeList { + + + //////////////////////////////////////////////////////////////////// + // Iteration methods. + //////////////////////////////////////////////////////////////////// + + + /** + * Return the number of attributes in this list. + * + *

The SAX parser may provide attributes in any + * arbitrary order, regardless of the order in which they were + * declared or specified. The number of attributes may be + * zero.

+ * + * @return The number of attributes in the list. + */ + public abstract int getLength (); + + + /** + * Return the name of an attribute in this list (by position). + * + *

The names must be unique: the SAX parser shall not include the + * same attribute twice. Attributes without values (those declared + * #IMPLIED without a value specified in the start tag) will be + * omitted from the list.

+ * + *

If the attribute name has a namespace prefix, the prefix + * will still be attached.

+ * + * @param i The index of the attribute in the list (starting at 0). + * @return The name of the indexed attribute, or null + * if the index is out of range. + * @see #getLength + */ + public abstract String getName (int i); + + + /** + * Return the type of an attribute in the list (by position). + * + *

The attribute type is one of the strings "CDATA", "ID", + * "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES", + * or "NOTATION" (always in upper case).

+ * + *

If the parser has not read a declaration for the attribute, + * or if the parser does not report attribute types, then it must + * return the value "CDATA" as stated in the XML 1.0 Recommentation + * (clause 3.3.3, "Attribute-Value Normalization").

+ * + *

For an enumerated attribute that is not a notation, the + * parser will report the type as "NMTOKEN".

+ * + * @param i The index of the attribute in the list (starting at 0). + * @return The attribute type as a string, or + * null if the index is out of range. + * @see #getLength + * @see #getType(java.lang.String) + */ + public abstract String getType (int i); + + + /** + * Return the value of an attribute in the list (by position). + * + *

If the attribute value is a list of tokens (IDREFS, + * ENTITIES, or NMTOKENS), the tokens will be concatenated + * into a single string separated by whitespace.

+ * + * @param i The index of the attribute in the list (starting at 0). + * @return The attribute value as a string, or + * null if the index is out of range. + * @see #getLength + * @see #getValue(java.lang.String) + */ + public abstract String getValue (int i); + + + + //////////////////////////////////////////////////////////////////// + // Lookup methods. + //////////////////////////////////////////////////////////////////// + + + /** + * Return the type of an attribute in the list (by name). + * + *

The return value is the same as the return value for + * getType(int).

+ * + *

If the attribute name has a namespace prefix in the document, + * the application must include the prefix here.

+ * + * @param name The name of the attribute. + * @return The attribute type as a string, or null if no + * such attribute exists. + * @see #getType(int) + */ + public abstract String getType (String name); + + + /** + * Return the value of an attribute in the list (by name). + * + *

The return value is the same as the return value for + * getValue(int).

+ * + *

If the attribute name has a namespace prefix in the document, + * the application must include the prefix here.

+ * + * @param name the name of the attribute to return + * @return The attribute value as a string, or null if + * no such attribute exists. + * @see #getValue(int) + */ + public abstract String getValue (String name); + +} + +// end of AttributeList.java diff --git a/src/org/xml/sax/Attributes.java b/src/org/xml/sax/Attributes.java new file mode 100644 index 0000000..b25432d --- /dev/null +++ b/src/org/xml/sax/Attributes.java @@ -0,0 +1,257 @@ +// Attributes.java - attribute list with Namespace support +// http://www.saxproject.org +// Written by David Megginson +// NO WARRANTY! This class is in the public domain. +// $Id: Attributes.java,v 1.13 2004/03/18 12:28:05 dmegginson Exp $ + +package org.xml.sax; + + +/** + * Interface for a list of XML attributes. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This interface allows access to a list of attributes in + * three different ways:

+ * + *
    + *
  1. by attribute index;
  2. + *
  3. by Namespace-qualified name; or
  4. + *
  5. by qualified (prefixed) name.
  6. + *
+ * + *

The list will not contain attributes that were declared + * #IMPLIED but not specified in the start tag. It will also not + * contain attributes used as Namespace declarations (xmlns*) unless + * the http://xml.org/sax/features/namespace-prefixes + * feature is set to true (it is false by + * default). + * Because SAX2 conforms to the original "Namespaces in XML" + * recommendation, it normally does not + * give namespace declaration attributes a namespace URI. + *

+ * + *

Some SAX2 parsers may support using an optional feature flag + * (http://xml.org/sax/features/xmlns-uris) to request + * that those attributes be given URIs, conforming to a later + * backwards-incompatible revision of that recommendation. (The + * attribute's "local name" will be the prefix, or "xmlns" when + * defining a default element namespace.) For portability, handler + * code should always resolve that conflict, rather than requiring + * parsers that can change the setting of that feature flag.

+ * + *

If the namespace-prefixes feature (see above) is + * false, access by qualified name may not be available; if + * the http://xml.org/sax/features/namespaces feature is + * false, access by Namespace-qualified names may not be + * available.

+ * + *

This interface replaces the now-deprecated SAX1 {@link + * org.xml.sax.AttributeList AttributeList} interface, which does not + * contain Namespace support. In addition to Namespace support, it + * adds the getIndex methods (below).

+ * + *

The order of attributes in the list is unspecified, and will + * vary from implementation to implementation.

+ * + * @since SAX 2.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.helpers.AttributesImpl + * @see org.xml.sax.ext.DeclHandler#attributeDecl + */ +public interface Attributes +{ + + + //////////////////////////////////////////////////////////////////// + // Indexed access. + //////////////////////////////////////////////////////////////////// + + + /** + * Return the number of attributes in the list. + * + *

Once you know the number of attributes, you can iterate + * through the list.

+ * + * @return The number of attributes in the list. + * @see #getURI(int) + * @see #getLocalName(int) + * @see #getQName(int) + * @see #getType(int) + * @see #getValue(int) + */ + public abstract int getLength (); + + + /** + * Look up an attribute's Namespace URI by index. + * + * @param index The attribute index (zero-based). + * @return The Namespace URI, or the empty string if none + * is available, or null if the index is out of + * range. + * @see #getLength + */ + public abstract String getURI (int index); + + + /** + * Look up an attribute's local name by index. + * + * @param index The attribute index (zero-based). + * @return The local name, or the empty string if Namespace + * processing is not being performed, or null + * if the index is out of range. + * @see #getLength + */ + public abstract String getLocalName (int index); + + + /** + * Look up an attribute's XML qualified (prefixed) name by index. + * + * @param index The attribute index (zero-based). + * @return The XML qualified name, or the empty string + * if none is available, or null if the index + * is out of range. + * @see #getLength + */ + public abstract String getQName (int index); + + + /** + * Look up an attribute's type by index. + * + *

The attribute type is one of the strings "CDATA", "ID", + * "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES", + * or "NOTATION" (always in upper case).

+ * + *

If the parser has not read a declaration for the attribute, + * or if the parser does not report attribute types, then it must + * return the value "CDATA" as stated in the XML 1.0 Recommendation + * (clause 3.3.3, "Attribute-Value Normalization").

+ * + *

For an enumerated attribute that is not a notation, the + * parser will report the type as "NMTOKEN".

+ * + * @param index The attribute index (zero-based). + * @return The attribute's type as a string, or null if the + * index is out of range. + * @see #getLength + */ + public abstract String getType (int index); + + + /** + * Look up an attribute's value by index. + * + *

If the attribute value is a list of tokens (IDREFS, + * ENTITIES, or NMTOKENS), the tokens will be concatenated + * into a single string with each token separated by a + * single space.

+ * + * @param index The attribute index (zero-based). + * @return The attribute's value as a string, or null if the + * index is out of range. + * @see #getLength + */ + public abstract String getValue (int index); + + + + //////////////////////////////////////////////////////////////////// + // Name-based query. + //////////////////////////////////////////////////////////////////// + + + /** + * Look up the index of an attribute by Namespace name. + * + * @param uri The Namespace URI, or the empty string if + * the name has no Namespace URI. + * @param localName The attribute's local name. + * @return The index of the attribute, or -1 if it does not + * appear in the list. + */ + public int getIndex (String uri, String localName); + + + /** + * Look up the index of an attribute by XML qualified (prefixed) name. + * + * @param qName The qualified (prefixed) name. + * @return The index of the attribute, or -1 if it does not + * appear in the list. + */ + public int getIndex (String qName); + + + /** + * Look up an attribute's type by Namespace name. + * + *

See {@link #getType(int) getType(int)} for a description + * of the possible types.

+ * + * @param uri The Namespace URI, or the empty String if the + * name has no Namespace URI. + * @param localName The local name of the attribute. + * @return The attribute type as a string, or null if the + * attribute is not in the list or if Namespace + * processing is not being performed. + */ + public abstract String getType (String uri, String localName); + + + /** + * Look up an attribute's type by XML qualified (prefixed) name. + * + *

See {@link #getType(int) getType(int)} for a description + * of the possible types.

+ * + * @param qName The XML qualified name. + * @return The attribute type as a string, or null if the + * attribute is not in the list or if qualified names + * are not available. + */ + public abstract String getType (String qName); + + + /** + * Look up an attribute's value by Namespace name. + * + *

See {@link #getValue(int) getValue(int)} for a description + * of the possible values.

+ * + * @param uri The Namespace URI, or the empty String if the + * name has no Namespace URI. + * @param localName The local name of the attribute. + * @return The attribute value as a string, or null if the + * attribute is not in the list. + */ + public abstract String getValue (String uri, String localName); + + + /** + * Look up an attribute's value by XML qualified (prefixed) name. + * + *

See {@link #getValue(int) getValue(int)} for a description + * of the possible values.

+ * + * @param qName The XML qualified name. + * @return The attribute value as a string, or null if the + * attribute is not in the list or if qualified names + * are not available. + */ + public abstract String getValue (String qName); + +} + +// end of Attributes.java diff --git a/src/org/xml/sax/ContentHandler.java b/src/org/xml/sax/ContentHandler.java new file mode 100644 index 0000000..3d95c5f --- /dev/null +++ b/src/org/xml/sax/ContentHandler.java @@ -0,0 +1,419 @@ +// ContentHandler.java - handle main document content. +// http://www.saxproject.org +// Written by David Megginson +// NO WARRANTY! This class is in the public domain. +// $Id: ContentHandler.java,v 1.13 2004/04/26 17:50:49 dmegginson Exp $ + +package org.xml.sax; + + +/** + * Receive notification of the logical content of a document. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This is the main interface that most SAX applications + * implement: if the application needs to be informed of basic parsing + * events, it implements this interface and registers an instance with + * the SAX parser using the {@link org.xml.sax.XMLReader#setContentHandler + * setContentHandler} method. The parser uses the instance to report + * basic document-related events like the start and end of elements + * and character data.

+ * + *

The order of events in this interface is very important, and + * mirrors the order of information in the document itself. For + * example, all of an element's content (character data, processing + * instructions, and/or subelements) will appear, in order, between + * the startElement event and the corresponding endElement event.

+ * + *

This interface is similar to the now-deprecated SAX 1.0 + * DocumentHandler interface, but it adds support for Namespaces + * and for reporting skipped entities (in non-validating XML + * processors).

+ * + *

Implementors should note that there is also a + * ContentHandler class in the java.net + * package; that means that it's probably a bad idea to do

+ * + *
import java.net.*;
+ * import org.xml.sax.*;
+ * 
+ * + *

In fact, "import ...*" is usually a sign of sloppy programming + * anyway, so the user should consider this a feature rather than a + * bug.

+ * + * @since SAX 2.0 + * @author David Megginson + * @version 2.0.1+ (sax2r3pre1) + * @see org.xml.sax.XMLReader + * @see org.xml.sax.DTDHandler + * @see org.xml.sax.ErrorHandler + */ +public interface ContentHandler +{ + + /** + * Receive an object for locating the origin of SAX document events. + * + *

SAX parsers are strongly encouraged (though not absolutely + * required) to supply a locator: if it does so, it must supply + * the locator to the application by invoking this method before + * invoking any of the other methods in the ContentHandler + * interface.

+ * + *

The locator allows the application to determine the end + * position of any document-related event, even if the parser is + * not reporting an error. Typically, the application will + * use this information for reporting its own errors (such as + * character content that does not match an application's + * business rules). The information returned by the locator + * is probably not sufficient for use with a search engine.

+ * + *

Note that the locator will return correct information only + * during the invocation SAX event callbacks after + * {@link #startDocument startDocument} returns and before + * {@link #endDocument endDocument} is called. The + * application should not attempt to use it at any other time.

+ * + * @param locator an object that can return the location of + * any SAX document event + * @see org.xml.sax.Locator + */ + public void setDocumentLocator (Locator locator); + + + /** + * Receive notification of the beginning of a document. + * + *

The SAX parser will invoke this method only once, before any + * other event callbacks (except for {@link #setDocumentLocator + * setDocumentLocator}).

+ * + * @throws org.xml.sax.SAXException any SAX exception, possibly + * wrapping another exception + * @see #endDocument + */ + public void startDocument () + throws SAXException; + + + /** + * Receive notification of the end of a document. + * + *

There is an apparent contradiction between the + * documentation for this method and the documentation for {@link + * org.xml.sax.ErrorHandler#fatalError}. Until this ambiguity is + * resolved in a future major release, clients should make no + * assumptions about whether endDocument() will or will not be + * invoked when the parser has reported a fatalError() or thrown + * an exception.

+ * + *

The SAX parser will invoke this method only once, and it will + * be the last method invoked during the parse. The parser shall + * not invoke this method until it has either abandoned parsing + * (because of an unrecoverable error) or reached the end of + * input.

+ * + * @throws org.xml.sax.SAXException any SAX exception, possibly + * wrapping another exception + * @see #startDocument + */ + public void endDocument() + throws SAXException; + + + /** + * Begin the scope of a prefix-URI Namespace mapping. + * + *

The information from this event is not necessary for + * normal Namespace processing: the SAX XML reader will + * automatically replace prefixes for element and attribute + * names when the http://xml.org/sax/features/namespaces + * feature is true (the default).

+ * + *

There are cases, however, when applications need to + * use prefixes in character data or in attribute values, + * where they cannot safely be expanded automatically; the + * start/endPrefixMapping event supplies the information + * to the application to expand prefixes in those contexts + * itself, if necessary.

+ * + *

Note that start/endPrefixMapping events are not + * guaranteed to be properly nested relative to each other: + * all startPrefixMapping events will occur immediately before the + * corresponding {@link #startElement startElement} event, + * and all {@link #endPrefixMapping endPrefixMapping} + * events will occur immediately after the corresponding + * {@link #endElement endElement} event, + * but their order is not otherwise + * guaranteed.

+ * + *

There should never be start/endPrefixMapping events for the + * "xml" prefix, since it is predeclared and immutable.

+ * + * @param prefix the Namespace prefix being declared. + * An empty string is used for the default element namespace, + * which has no prefix. + * @param uri the Namespace URI the prefix is mapped to + * @throws org.xml.sax.SAXException the client may throw + * an exception during processing + * @see #endPrefixMapping + * @see #startElement + */ + public void startPrefixMapping (String prefix, String uri) + throws SAXException; + + + /** + * End the scope of a prefix-URI mapping. + * + *

See {@link #startPrefixMapping startPrefixMapping} for + * details. These events will always occur immediately after the + * corresponding {@link #endElement endElement} event, but the order of + * {@link #endPrefixMapping endPrefixMapping} events is not otherwise + * guaranteed.

+ * + * @param prefix the prefix that was being mapped. + * This is the empty string when a default mapping scope ends. + * @throws org.xml.sax.SAXException the client may throw + * an exception during processing + * @see #startPrefixMapping + * @see #endElement + */ + public void endPrefixMapping (String prefix) + throws SAXException; + + + /** + * Receive notification of the beginning of an element. + * + *

The Parser will invoke this method at the beginning of every + * element in the XML document; there will be a corresponding + * {@link #endElement endElement} event for every startElement event + * (even when the element is empty). All of the element's content will be + * reported, in order, before the corresponding endElement + * event.

+ * + *

This event allows up to three name components for each + * element:

+ * + *
    + *
  1. the Namespace URI;
  2. + *
  3. the local name; and
  4. + *
  5. the qualified (prefixed) name.
  6. + *
+ * + *

Any or all of these may be provided, depending on the + * values of the http://xml.org/sax/features/namespaces + * and the http://xml.org/sax/features/namespace-prefixes + * properties:

+ * + *
    + *
  • the Namespace URI and local name are required when + * the namespaces property is true (the default), and are + * optional when the namespaces property is false (if one is + * specified, both must be);
  • + *
  • the qualified name is required when the namespace-prefixes property + * is true, and is optional when the namespace-prefixes property + * is false (the default).
  • + *
+ * + *

Note that the attribute list provided will contain only + * attributes with explicit values (specified or defaulted): + * #IMPLIED attributes will be omitted. The attribute list + * will contain attributes used for Namespace declarations + * (xmlns* attributes) only if the + * http://xml.org/sax/features/namespace-prefixes + * property is true (it is false by default, and support for a + * true value is optional).

+ * + *

Like {@link #characters characters()}, attribute values may have + * characters that need more than one char value.

+ * + * @param uri the Namespace URI, or the empty string if the + * element has no Namespace URI or if Namespace + * processing is not being performed + * @param localName the local name (without prefix), or the + * empty string if Namespace processing is not being + * performed + * @param qName the qualified name (with prefix), or the + * empty string if qualified names are not available + * @param atts the attributes attached to the element. If + * there are no attributes, it shall be an empty + * Attributes object. The value of this object after + * startElement returns is undefined + * @throws org.xml.sax.SAXException any SAX exception, possibly + * wrapping another exception + * @see #endElement + * @see org.xml.sax.Attributes + * @see org.xml.sax.helpers.AttributesImpl + */ + public void startElement (String uri, String localName, + String qName, Attributes atts) + throws SAXException; + + + /** + * Receive notification of the end of an element. + * + *

The SAX parser will invoke this method at the end of every + * element in the XML document; there will be a corresponding + * {@link #startElement startElement} event for every endElement + * event (even when the element is empty).

+ * + *

For information on the names, see startElement.

+ * + * @param uri the Namespace URI, or the empty string if the + * element has no Namespace URI or if Namespace + * processing is not being performed + * @param localName the local name (without prefix), or the + * empty string if Namespace processing is not being + * performed + * @param qName the qualified XML name (with prefix), or the + * empty string if qualified names are not available + * @throws org.xml.sax.SAXException any SAX exception, possibly + * wrapping another exception + */ + public void endElement (String uri, String localName, + String qName) + throws SAXException; + + + /** + * Receive notification of character data. + * + *

The Parser will call this method to report each chunk of + * character data. SAX parsers may return all contiguous character + * data in a single chunk, or they may split it into several + * chunks; however, all of the characters in any single event + * must come from the same external entity so that the Locator + * provides useful information.

+ * + *

The application must not attempt to read from the array + * outside of the specified range.

+ * + *

Individual characters may consist of more than one Java + * char value. There are two important cases where this + * happens, because characters can't be represented in just sixteen bits. + * In one case, characters are represented in a Surrogate Pair, + * using two special Unicode values. Such characters are in the so-called + * "Astral Planes", with a code point above U+FFFF. A second case involves + * composite characters, such as a base character combining with one or + * more accent characters.

+ * + *

Your code should not assume that algorithms using + * char-at-a-time idioms will be working in character + * units; in some cases they will split characters. This is relevant + * wherever XML permits arbitrary characters, such as attribute values, + * processing instruction data, and comments as well as in data reported + * from this method. It's also generally relevant whenever Java code + * manipulates internationalized text; the issue isn't unique to XML.

+ * + *

Note that some parsers will report whitespace in element + * content using the {@link #ignorableWhitespace ignorableWhitespace} + * method rather than this one (validating parsers must + * do so).

+ * + * @param ch the characters from the XML document + * @param start the start position in the array + * @param length the number of characters to read from the array + * @throws org.xml.sax.SAXException any SAX exception, possibly + * wrapping another exception + * @see #ignorableWhitespace + * @see org.xml.sax.Locator + */ + public void characters (char ch[], int start, int length) + throws SAXException; + + + /** + * Receive notification of ignorable whitespace in element content. + * + *

Validating Parsers must use this method to report each chunk + * of whitespace in element content (see the W3C XML 1.0 + * recommendation, section 2.10): non-validating parsers may also + * use this method if they are capable of parsing and using + * content models.

+ * + *

SAX parsers may return all contiguous whitespace in a single + * chunk, or they may split it into several chunks; however, all of + * the characters in any single event must come from the same + * external entity, so that the Locator provides useful + * information.

+ * + *

The application must not attempt to read from the array + * outside of the specified range.

+ * + * @param ch the characters from the XML document + * @param start the start position in the array + * @param length the number of characters to read from the array + * @throws org.xml.sax.SAXException any SAX exception, possibly + * wrapping another exception + * @see #characters + */ + public void ignorableWhitespace (char ch[], int start, int length) + throws SAXException; + + + /** + * Receive notification of a processing instruction. + * + *

The Parser will invoke this method once for each processing + * instruction found: note that processing instructions may occur + * before or after the main document element.

+ * + *

A SAX parser must never report an XML declaration (XML 1.0, + * section 2.8) or a text declaration (XML 1.0, section 4.3.1) + * using this method.

+ * + *

Like {@link #characters characters()}, processing instruction + * data may have characters that need more than one char + * value.

+ * + * @param target the processing instruction target + * @param data the processing instruction data, or null if + * none was supplied. The data does not include any + * whitespace separating it from the target + * @throws org.xml.sax.SAXException any SAX exception, possibly + * wrapping another exception + */ + public void processingInstruction (String target, String data) + throws SAXException; + + + /** + * Receive notification of a skipped entity. + * This is not called for entity references within markup constructs + * such as element start tags or markup declarations. (The XML + * recommendation requires reporting skipped external entities. + * SAX also reports internal entity expansion/non-expansion, except + * within markup constructs.) + * + *

The Parser will invoke this method each time the entity is + * skipped. Non-validating processors may skip entities if they + * have not seen the declarations (because, for example, the + * entity was declared in an external DTD subset). All processors + * may skip external entities, depending on the values of the + * http://xml.org/sax/features/external-general-entities + * and the + * http://xml.org/sax/features/external-parameter-entities + * properties.

+ * + * @param name the name of the skipped entity. If it is a + * parameter entity, the name will begin with '%', and if + * it is the external DTD subset, it will be the string + * "[dtd]" + * @throws org.xml.sax.SAXException any SAX exception, possibly + * wrapping another exception + */ + public void skippedEntity (String name) + throws SAXException; +} + +// end of ContentHandler.java diff --git a/src/org/xml/sax/DTDHandler.java b/src/org/xml/sax/DTDHandler.java new file mode 100644 index 0000000..e62222a --- /dev/null +++ b/src/org/xml/sax/DTDHandler.java @@ -0,0 +1,117 @@ +// SAX DTD handler. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: DTDHandler.java,v 1.8 2002/01/30 21:13:43 dbrownell Exp $ + +package org.xml.sax; + +/** + * Receive notification of basic DTD-related events. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

If a SAX application needs information about notations and + * unparsed entities, then the application implements this + * interface and registers an instance with the SAX parser using + * the parser's setDTDHandler method. The parser uses the + * instance to report notation and unparsed entity declarations to + * the application.

+ * + *

Note that this interface includes only those DTD events that + * the XML recommendation requires processors to report: + * notation and unparsed entity declarations.

+ * + *

The SAX parser may report these events in any order, regardless + * of the order in which the notations and unparsed entities were + * declared; however, all DTD events must be reported after the + * document handler's startDocument event, and before the first + * startElement event. + * (If the {@link org.xml.sax.ext.LexicalHandler LexicalHandler} is + * used, these events must also be reported before the endDTD event.) + *

+ * + *

It is up to the application to store the information for + * future use (perhaps in a hash table or object tree). + * If the application encounters attributes of type "NOTATION", + * "ENTITY", or "ENTITIES", it can use the information that it + * obtained through this interface to find the entity and/or + * notation corresponding with the attribute value.

+ * + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.XMLReader#setDTDHandler + */ +public interface DTDHandler { + + + /** + * Receive notification of a notation declaration event. + * + *

It is up to the application to record the notation for later + * reference, if necessary; + * notations may appear as attribute values and in unparsed entity + * declarations, and are sometime used with processing instruction + * target names.

+ * + *

At least one of publicId and systemId must be non-null. + * If a system identifier is present, and it is a URL, the SAX + * parser must resolve it fully before passing it to the + * application through this event.

+ * + *

There is no guarantee that the notation declaration will be + * reported before any unparsed entities that use it.

+ * + * @param name The notation name. + * @param publicId The notation's public identifier, or null if + * none was given. + * @param systemId The notation's system identifier, or null if + * none was given. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see #unparsedEntityDecl + * @see org.xml.sax.Attributes + */ + public abstract void notationDecl (String name, + String publicId, + String systemId) + throws SAXException; + + + /** + * Receive notification of an unparsed entity declaration event. + * + *

Note that the notation name corresponds to a notation + * reported by the {@link #notationDecl notationDecl} event. + * It is up to the application to record the entity for later + * reference, if necessary; + * unparsed entities may appear as attribute values. + *

+ * + *

If the system identifier is a URL, the parser must resolve it + * fully before passing it to the application.

+ * + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @param name The unparsed entity's name. + * @param publicId The entity's public identifier, or null if none + * was given. + * @param systemId The entity's system identifier. + * @param notationName The name of the associated notation. + * @see #notationDecl + * @see org.xml.sax.Attributes + */ + public abstract void unparsedEntityDecl (String name, + String publicId, + String systemId, + String notationName) + throws SAXException; + +} + +// end of DTDHandler.java diff --git a/src/org/xml/sax/DocumentHandler.java b/src/org/xml/sax/DocumentHandler.java new file mode 100644 index 0000000..d70ae74 --- /dev/null +++ b/src/org/xml/sax/DocumentHandler.java @@ -0,0 +1,232 @@ +// SAX document handler. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: DocumentHandler.java,v 1.6 2002/01/30 21:13:43 dbrownell Exp $ + +package org.xml.sax; + +/** + * Receive notification of general document events. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This was the main event-handling interface for SAX1; in + * SAX2, it has been replaced by {@link org.xml.sax.ContentHandler + * ContentHandler}, which provides Namespace support and reporting + * of skipped entities. This interface is included in SAX2 only + * to support legacy SAX1 applications.

+ * + *

The order of events in this interface is very important, and + * mirrors the order of information in the document itself. For + * example, all of an element's content (character data, processing + * instructions, and/or subelements) will appear, in order, between + * the startElement event and the corresponding endElement event.

+ * + *

Application writers who do not want to implement the entire + * interface can derive a class from HandlerBase, which implements + * the default functionality; parser writers can instantiate + * HandlerBase to obtain a default handler. The application can find + * the location of any document event using the Locator interface + * supplied by the Parser through the setDocumentLocator method.

+ * + * @deprecated This interface has been replaced by the SAX2 + * {@link org.xml.sax.ContentHandler ContentHandler} + * interface, which includes Namespace support. + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.Parser#setDocumentHandler + * @see org.xml.sax.Locator + * @see org.xml.sax.HandlerBase + */ +public interface DocumentHandler { + + + /** + * Receive an object for locating the origin of SAX document events. + * + *

SAX parsers are strongly encouraged (though not absolutely + * required) to supply a locator: if it does so, it must supply + * the locator to the application by invoking this method before + * invoking any of the other methods in the DocumentHandler + * interface.

+ * + *

The locator allows the application to determine the end + * position of any document-related event, even if the parser is + * not reporting an error. Typically, the application will + * use this information for reporting its own errors (such as + * character content that does not match an application's + * business rules). The information returned by the locator + * is probably not sufficient for use with a search engine.

+ * + *

Note that the locator will return correct information only + * during the invocation of the events in this interface. The + * application should not attempt to use it at any other time.

+ * + * @param locator An object that can return the location of + * any SAX document event. + * @see org.xml.sax.Locator + */ + public abstract void setDocumentLocator (Locator locator); + + + /** + * Receive notification of the beginning of a document. + * + *

The SAX parser will invoke this method only once, before any + * other methods in this interface or in DTDHandler (except for + * setDocumentLocator).

+ * + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + */ + public abstract void startDocument () + throws SAXException; + + + /** + * Receive notification of the end of a document. + * + *

The SAX parser will invoke this method only once, and it will + * be the last method invoked during the parse. The parser shall + * not invoke this method until it has either abandoned parsing + * (because of an unrecoverable error) or reached the end of + * input.

+ * + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + */ + public abstract void endDocument () + throws SAXException; + + + /** + * Receive notification of the beginning of an element. + * + *

The Parser will invoke this method at the beginning of every + * element in the XML document; there will be a corresponding + * endElement() event for every startElement() event (even when the + * element is empty). All of the element's content will be + * reported, in order, before the corresponding endElement() + * event.

+ * + *

If the element name has a namespace prefix, the prefix will + * still be attached. Note that the attribute list provided will + * contain only attributes with explicit values (specified or + * defaulted): #IMPLIED attributes will be omitted.

+ * + * @param name The element type name. + * @param atts The attributes attached to the element, if any. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see #endElement + * @see org.xml.sax.AttributeList + */ + public abstract void startElement (String name, AttributeList atts) + throws SAXException; + + + /** + * Receive notification of the end of an element. + * + *

The SAX parser will invoke this method at the end of every + * element in the XML document; there will be a corresponding + * startElement() event for every endElement() event (even when the + * element is empty).

+ * + *

If the element name has a namespace prefix, the prefix will + * still be attached to the name.

+ * + * @param name The element type name + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + */ + public abstract void endElement (String name) + throws SAXException; + + + /** + * Receive notification of character data. + * + *

The Parser will call this method to report each chunk of + * character data. SAX parsers may return all contiguous character + * data in a single chunk, or they may split it into several + * chunks; however, all of the characters in any single event + * must come from the same external entity, so that the Locator + * provides useful information.

+ * + *

The application must not attempt to read from the array + * outside of the specified range.

+ * + *

Note that some parsers will report whitespace using the + * ignorableWhitespace() method rather than this one (validating + * parsers must do so).

+ * + * @param ch The characters from the XML document. + * @param start The start position in the array. + * @param length The number of characters to read from the array. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see #ignorableWhitespace + * @see org.xml.sax.Locator + */ + public abstract void characters (char ch[], int start, int length) + throws SAXException; + + + /** + * Receive notification of ignorable whitespace in element content. + * + *

Validating Parsers must use this method to report each chunk + * of ignorable whitespace (see the W3C XML 1.0 recommendation, + * section 2.10): non-validating parsers may also use this method + * if they are capable of parsing and using content models.

+ * + *

SAX parsers may return all contiguous whitespace in a single + * chunk, or they may split it into several chunks; however, all of + * the characters in any single event must come from the same + * external entity, so that the Locator provides useful + * information.

+ * + *

The application must not attempt to read from the array + * outside of the specified range.

+ * + * @param ch The characters from the XML document. + * @param start The start position in the array. + * @param length The number of characters to read from the array. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see #characters + */ + public abstract void ignorableWhitespace (char ch[], int start, int length) + throws SAXException; + + + /** + * Receive notification of a processing instruction. + * + *

The Parser will invoke this method once for each processing + * instruction found: note that processing instructions may occur + * before or after the main document element.

+ * + *

A SAX parser should never report an XML declaration (XML 1.0, + * section 2.8) or a text declaration (XML 1.0, section 4.3.1) + * using this method.

+ * + * @param target The processing instruction target. + * @param data The processing instruction data, or null if + * none was supplied. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + */ + public abstract void processingInstruction (String target, String data) + throws SAXException; + +} + +// end of DocumentHandler.java diff --git a/src/org/xml/sax/EntityResolver.java b/src/org/xml/sax/EntityResolver.java new file mode 100644 index 0000000..65b04eb --- /dev/null +++ b/src/org/xml/sax/EntityResolver.java @@ -0,0 +1,119 @@ +// SAX entity resolver. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: EntityResolver.java,v 1.10 2002/01/30 21:13:44 dbrownell Exp $ + +package org.xml.sax; + +import java.io.IOException; + + +/** + * Basic interface for resolving entities. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

If a SAX application needs to implement customized handling + * for external entities, it must implement this interface and + * register an instance with the SAX driver using the + * {@link org.xml.sax.XMLReader#setEntityResolver setEntityResolver} + * method.

+ * + *

The XML reader will then allow the application to intercept any + * external entities (including the external DTD subset and external + * parameter entities, if any) before including them.

+ * + *

Many SAX applications will not need to implement this interface, + * but it will be especially useful for applications that build + * XML documents from databases or other specialised input sources, + * or for applications that use URI types other than URLs.

+ * + *

The following resolver would provide the application + * with a special character stream for the entity with the system + * identifier "http://www.myhost.com/today":

+ * + *
+ * import org.xml.sax.EntityResolver;
+ * import org.xml.sax.InputSource;
+ *
+ * public class MyResolver implements EntityResolver {
+ *   public InputSource resolveEntity (String publicId, String systemId)
+ *   {
+ *     if (systemId.equals("http://www.myhost.com/today")) {
+ *              // return a special input source
+ *       MyReader reader = new MyReader();
+ *       return new InputSource(reader);
+ *     } else {
+ *              // use the default behaviour
+ *       return null;
+ *     }
+ *   }
+ * }
+ * 
+ * + *

The application can also use this interface to redirect system + * identifiers to local URIs or to look up replacements in a catalog + * (possibly by using the public identifier).

+ * + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.XMLReader#setEntityResolver + * @see org.xml.sax.InputSource + */ +public interface EntityResolver { + + + /** + * Allow the application to resolve external entities. + * + *

The parser will call this method before opening any external + * entity except the top-level document entity. Such entities include + * the external DTD subset and external parameter entities referenced + * within the DTD (in either case, only if the parser reads external + * parameter entities), and external general entities referenced + * within the document element (if the parser reads external general + * entities). The application may request that the parser locate + * the entity itself, that it use an alternative URI, or that it + * use data provided by the application (as a character or byte + * input stream).

+ * + *

Application writers can use this method to redirect external + * system identifiers to secure and/or local URIs, to look up + * public identifiers in a catalogue, or to read an entity from a + * database or other input source (including, for example, a dialog + * box). Neither XML nor SAX specifies a preferred policy for using + * public or system IDs to resolve resources. However, SAX specifies + * how to interpret any InputSource returned by this method, and that + * if none is returned, then the system ID will be dereferenced as + * a URL.

+ * + *

If the system identifier is a URL, the SAX parser must + * resolve it fully before reporting it to the application.

+ * + * @param publicId The public identifier of the external entity + * being referenced, or null if none was supplied. + * @param systemId The system identifier of the external entity + * being referenced. + * @return An InputSource object describing the new input source, + * or null to request that the parser open a regular + * URI connection to the system identifier. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @exception java.io.IOException A Java-specific IO exception, + * possibly the result of creating a new InputStream + * or Reader for the InputSource. + * @see org.xml.sax.InputSource + */ + public abstract InputSource resolveEntity (String publicId, + String systemId) + throws SAXException, IOException; + +} + +// end of EntityResolver.java diff --git a/src/org/xml/sax/ErrorHandler.java b/src/org/xml/sax/ErrorHandler.java new file mode 100644 index 0000000..37d2501 --- /dev/null +++ b/src/org/xml/sax/ErrorHandler.java @@ -0,0 +1,139 @@ +// SAX error handler. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: ErrorHandler.java,v 1.10 2004/03/08 13:01:00 dmegginson Exp $ + +package org.xml.sax; + + +/** + * Basic interface for SAX error handlers. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

If a SAX application needs to implement customized error + * handling, it must implement this interface and then register an + * instance with the XML reader using the + * {@link org.xml.sax.XMLReader#setErrorHandler setErrorHandler} + * method. The parser will then report all errors and warnings + * through this interface.

+ * + *

WARNING: If an application does not + * register an ErrorHandler, XML parsing errors will go unreported, + * except that SAXParseExceptions will be thrown for fatal errors. + * In order to detect validity errors, an ErrorHandler that does something + * with {@link #error error()} calls must be registered.

+ * + *

For XML processing errors, a SAX driver must use this interface + * in preference to throwing an exception: it is up to the application + * to decide whether to throw an exception for different types of + * errors and warnings. Note, however, that there is no requirement that + * the parser continue to report additional errors after a call to + * {@link #fatalError fatalError}. In other words, a SAX driver class + * may throw an exception after reporting any fatalError. + * Also parsers may throw appropriate exceptions for non-XML errors. + * For example, {@link XMLReader#parse XMLReader.parse()} would throw + * an IOException for errors accessing entities or the document.

+ * + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1+ (sax2r3pre1) + * @see org.xml.sax.XMLReader#setErrorHandler + * @see org.xml.sax.SAXParseException + */ +public interface ErrorHandler { + + + /** + * Receive notification of a warning. + * + *

SAX parsers will use this method to report conditions that + * are not errors or fatal errors as defined by the XML + * recommendation. The default behaviour is to take no + * action.

+ * + *

The SAX parser must continue to provide normal parsing events + * after invoking this method: it should still be possible for the + * application to process the document through to the end.

+ * + *

Filters may use this method to report other, non-XML warnings + * as well.

+ * + * @param exception The warning information encapsulated in a + * SAX parse exception. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.SAXParseException + */ + public abstract void warning (SAXParseException exception) + throws SAXException; + + + /** + * Receive notification of a recoverable error. + * + *

This corresponds to the definition of "error" in section 1.2 + * of the W3C XML 1.0 Recommendation. For example, a validating + * parser would use this callback to report the violation of a + * validity constraint. The default behaviour is to take no + * action.

+ * + *

The SAX parser must continue to provide normal parsing + * events after invoking this method: it should still be possible + * for the application to process the document through to the end. + * If the application cannot do so, then the parser should report + * a fatal error even if the XML recommendation does not require + * it to do so.

+ * + *

Filters may use this method to report other, non-XML errors + * as well.

+ * + * @param exception The error information encapsulated in a + * SAX parse exception. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.SAXParseException + */ + public abstract void error (SAXParseException exception) + throws SAXException; + + + /** + * Receive notification of a non-recoverable error. + * + *

There is an apparent contradiction between the + * documentation for this method and the documentation for {@link + * org.xml.sax.ContentHandler#endDocument}. Until this ambiguity + * is resolved in a future major release, clients should make no + * assumptions about whether endDocument() will or will not be + * invoked when the parser has reported a fatalError() or thrown + * an exception.

+ * + *

This corresponds to the definition of "fatal error" in + * section 1.2 of the W3C XML 1.0 Recommendation. For example, a + * parser would use this callback to report the violation of a + * well-formedness constraint.

+ * + *

The application must assume that the document is unusable + * after the parser has invoked this method, and should continue + * (if at all) only for the sake of collecting additional error + * messages: in fact, SAX parsers are free to stop reporting any + * other events once this method has been invoked.

+ * + * @param exception The error information encapsulated in a + * SAX parse exception. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.SAXParseException + */ + public abstract void fatalError (SAXParseException exception) + throws SAXException; + +} + +// end of ErrorHandler.java diff --git a/src/org/xml/sax/HandlerBase.java b/src/org/xml/sax/HandlerBase.java new file mode 100644 index 0000000..7c5c411 --- /dev/null +++ b/src/org/xml/sax/HandlerBase.java @@ -0,0 +1,383 @@ +// SAX default handler base class. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: HandlerBase.java,v 1.7 2004/04/26 17:34:34 dmegginson Exp $ + +package org.xml.sax; + +/** + * Default base class for handlers. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This class implements the default behaviour for four SAX1 + * interfaces: EntityResolver, DTDHandler, DocumentHandler, + * and ErrorHandler. It is now obsolete, but is included in SAX2 to + * support legacy SAX1 applications. SAX2 applications should use + * the {@link org.xml.sax.helpers.DefaultHandler DefaultHandler} + * class instead.

+ * + *

Application writers can extend this class when they need to + * implement only part of an interface; parser writers can + * instantiate this class to provide default handlers when the + * application has not supplied its own.

+ * + *

Note that the use of this class is optional.

+ * + * @deprecated This class works with the deprecated + * {@link org.xml.sax.DocumentHandler DocumentHandler} + * interface. It has been replaced by the SAX2 + * {@link org.xml.sax.helpers.DefaultHandler DefaultHandler} + * class. + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.EntityResolver + * @see org.xml.sax.DTDHandler + * @see org.xml.sax.DocumentHandler + * @see org.xml.sax.ErrorHandler + */ +public class HandlerBase + implements EntityResolver, DTDHandler, DocumentHandler, ErrorHandler +{ + + + //////////////////////////////////////////////////////////////////// + // Default implementation of the EntityResolver interface. + //////////////////////////////////////////////////////////////////// + + /** + * Resolve an external entity. + * + *

Always return null, so that the parser will use the system + * identifier provided in the XML document. This method implements + * the SAX default behaviour: application writers can override it + * in a subclass to do special translations such as catalog lookups + * or URI redirection.

+ * + * @param publicId The public identifer, or null if none is + * available. + * @param systemId The system identifier provided in the XML + * document. + * @return The new input source, or null to require the + * default behaviour. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.EntityResolver#resolveEntity + */ + @Override + public InputSource resolveEntity (String publicId, String systemId) + throws SAXException + { + return null; + } + + + + //////////////////////////////////////////////////////////////////// + // Default implementation of DTDHandler interface. + //////////////////////////////////////////////////////////////////// + + + /** + * Receive notification of a notation declaration. + * + *

By default, do nothing. Application writers may override this + * method in a subclass if they wish to keep track of the notations + * declared in a document.

+ * + * @param name The notation name. + * @param publicId The notation public identifier, or null if not + * available. + * @param systemId The notation system identifier. + * @see org.xml.sax.DTDHandler#notationDecl + */ + @Override + public void notationDecl (String name, String publicId, String systemId) + { + // no op + } + + + /** + * Receive notification of an unparsed entity declaration. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to keep track of the unparsed entities + * declared in a document.

+ * + * @param name The entity name. + * @param publicId The entity public identifier, or null if not + * available. + * @param systemId The entity system identifier. + * @param notationName The name of the associated notation. + * @see org.xml.sax.DTDHandler#unparsedEntityDecl + */ + @Override + public void unparsedEntityDecl (String name, String publicId, + String systemId, String notationName) + { + // no op + } + + + + //////////////////////////////////////////////////////////////////// + // Default implementation of DocumentHandler interface. + //////////////////////////////////////////////////////////////////// + + + /** + * Receive a Locator object for document events. + * + *

By default, do nothing. Application writers may override this + * method in a subclass if they wish to store the locator for use + * with other document events.

+ * + * @param locator A locator for all SAX document events. + * @see org.xml.sax.DocumentHandler#setDocumentLocator + * @see org.xml.sax.Locator + */ + @Override + public void setDocumentLocator (Locator locator) + { + // no op + } + + + /** + * Receive notification of the beginning of the document. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions at the beginning + * of a document (such as allocating the root node of a tree or + * creating an output file).

+ * + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.DocumentHandler#startDocument + */ + @Override + public void startDocument () + throws SAXException + { + // no op + } + + + /** + * Receive notification of the end of the document. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions at the beginning + * of a document (such as finalising a tree or closing an output + * file).

+ * + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.DocumentHandler#endDocument + */ + @Override + public void endDocument () + throws SAXException + { + // no op + } + + + /** + * Receive notification of the start of an element. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions at the start of + * each element (such as allocating a new tree node or writing + * output to a file).

+ * + * @param name The element type name. + * @param attributes The specified or defaulted attributes. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.DocumentHandler#startElement + */ + @Override + public void startElement (String name, AttributeList attributes) + throws SAXException + { + // no op + } + + + /** + * Receive notification of the end of an element. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions at the end of + * each element (such as finalising a tree node or writing + * output to a file).

+ * + * @param name the element name + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.DocumentHandler#endElement + */ + @Override + public void endElement (String name) + throws SAXException + { + // no op + } + + + /** + * Receive notification of character data inside an element. + * + *

By default, do nothing. Application writers may override this + * method to take specific actions for each chunk of character data + * (such as adding the data to a node or buffer, or printing it to + * a file).

+ * + * @param ch The characters. + * @param start The start position in the character array. + * @param length The number of characters to use from the + * character array. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.DocumentHandler#characters + */ + @Override + public void characters (char ch[], int start, int length) + throws SAXException + { + // no op + } + + + /** + * Receive notification of ignorable whitespace in element content. + * + *

By default, do nothing. Application writers may override this + * method to take specific actions for each chunk of ignorable + * whitespace (such as adding data to a node or buffer, or printing + * it to a file).

+ * + * @param ch The whitespace characters. + * @param start The start position in the character array. + * @param length The number of characters to use from the + * character array. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.DocumentHandler#ignorableWhitespace + */ + @Override + public void ignorableWhitespace (char ch[], int start, int length) + throws SAXException + { + // no op + } + + + /** + * Receive notification of a processing instruction. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions for each + * processing instruction, such as setting status variables or + * invoking other methods.

+ * + * @param target The processing instruction target. + * @param data The processing instruction data, or null if + * none is supplied. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.DocumentHandler#processingInstruction + */ + @Override + public void processingInstruction (String target, String data) + throws SAXException + { + // no op + } + + + + //////////////////////////////////////////////////////////////////// + // Default implementation of the ErrorHandler interface. + //////////////////////////////////////////////////////////////////// + + + /** + * Receive notification of a parser warning. + * + *

The default implementation does nothing. Application writers + * may override this method in a subclass to take specific actions + * for each warning, such as inserting the message in a log file or + * printing it to the console.

+ * + * @param e The warning information encoded as an exception. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ErrorHandler#warning + * @see org.xml.sax.SAXParseException + */ + @Override + public void warning (SAXParseException e) + throws SAXException + { + // no op + } + + + /** + * Receive notification of a recoverable parser error. + * + *

The default implementation does nothing. Application writers + * may override this method in a subclass to take specific actions + * for each error, such as inserting the message in a log file or + * printing it to the console.

+ * + * @param e The warning information encoded as an exception. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ErrorHandler#warning + * @see org.xml.sax.SAXParseException + */ + @Override + public void error (SAXParseException e) + throws SAXException + { + // no op + } + + + /** + * Report a fatal XML parsing error. + * + *

The default implementation throws a SAXParseException. + * Application writers may override this method in a subclass if + * they need to take specific actions for each fatal error (such as + * collecting all of the errors into a single report): in any case, + * the application must stop all regular processing when this + * method is invoked, since the document is no longer reliable, and + * the parser may no longer report parsing events.

+ * + * @param e The error information encoded as an exception. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ErrorHandler#fatalError + * @see org.xml.sax.SAXParseException + */ + @Override + public void fatalError (SAXParseException e) + throws SAXException + { + throw e; + } + +} + +// end of HandlerBase.java diff --git a/src/org/xml/sax/InputSource.java b/src/org/xml/sax/InputSource.java new file mode 100644 index 0000000..663700c --- /dev/null +++ b/src/org/xml/sax/InputSource.java @@ -0,0 +1,336 @@ +// SAX input source. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: InputSource.java,v 1.9 2002/01/30 21:13:45 dbrownell Exp $ + +package org.xml.sax; + +import java.io.Reader; +import java.io.InputStream; + +/** + * A single input source for an XML entity. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This class allows a SAX application to encapsulate information + * about an input source in a single object, which may include + * a public identifier, a system identifier, a byte stream (possibly + * with a specified encoding), and/or a character stream.

+ * + *

There are two places that the application can deliver an + * input source to the parser: as the argument to the Parser.parse + * method, or as the return value of the EntityResolver.resolveEntity + * method.

+ * + *

The SAX parser will use the InputSource object to determine how + * to read XML input. If there is a character stream available, the + * parser will read that stream directly, disregarding any text + * encoding declaration found in that stream. + * If there is no character stream, but there is + * a byte stream, the parser will use that byte stream, using the + * encoding specified in the InputSource or else (if no encoding is + * specified) autodetecting the character encoding using an algorithm + * such as the one in the XML specification. If neither a character + * stream nor a + * byte stream is available, the parser will attempt to open a URI + * connection to the resource identified by the system + * identifier.

+ * + *

An InputSource object belongs to the application: the SAX parser + * shall never modify it in any way (it may modify a copy if + * necessary). However, standard processing of both byte and + * character streams is to close them on as part of end-of-parse cleanup, + * so applications should not attempt to re-use such streams after they + * have been handed to a parser.

+ * + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.XMLReader#parse(org.xml.sax.InputSource) + * @see org.xml.sax.EntityResolver#resolveEntity + * @see java.io.InputStream + * @see java.io.Reader + */ +public class InputSource { + + /** + * Zero-argument default constructor. + * + * @see #setPublicId + * @see #setSystemId + * @see #setByteStream + * @see #setCharacterStream + * @see #setEncoding + */ + public InputSource () + { + } + + + /** + * Create a new input source with a system identifier. + * + *

Applications may use setPublicId to include a + * public identifier as well, or setEncoding to specify + * the character encoding, if known.

+ * + *

If the system identifier is a URL, it must be fully + * resolved (it may not be a relative URL).

+ * + * @param systemId The system identifier (URI). + * @see #setPublicId + * @see #setSystemId + * @see #setByteStream + * @see #setEncoding + * @see #setCharacterStream + */ + public InputSource (String systemId) + { + setSystemId(systemId); + } + + + /** + * Create a new input source with a byte stream. + * + *

Application writers should use setSystemId() to provide a base + * for resolving relative URIs, may use setPublicId to include a + * public identifier, and may use setEncoding to specify the object's + * character encoding.

+ * + * @param byteStream The raw byte stream containing the document. + * @see #setPublicId + * @see #setSystemId + * @see #setEncoding + * @see #setByteStream + * @see #setCharacterStream + */ + public InputSource (InputStream byteStream) + { + setByteStream(byteStream); + } + + + /** + * Create a new input source with a character stream. + * + *

Application writers should use setSystemId() to provide a base + * for resolving relative URIs, and may use setPublicId to include a + * public identifier.

+ * + *

The character stream shall not include a byte order mark.

+ * + * @see #setPublicId + * @see #setSystemId + * @see #setByteStream + * @see #setCharacterStream + */ + public InputSource (Reader characterStream) + { + setCharacterStream(characterStream); + } + + + /** + * Set the public identifier for this input source. + * + *

The public identifier is always optional: if the application + * writer includes one, it will be provided as part of the + * location information.

+ * + * @param publicId The public identifier as a string. + * @see #getPublicId + * @see org.xml.sax.Locator#getPublicId + * @see org.xml.sax.SAXParseException#getPublicId + */ + public void setPublicId (String publicId) + { + this.publicId = publicId; + } + + + /** + * Get the public identifier for this input source. + * + * @return The public identifier, or null if none was supplied. + * @see #setPublicId + */ + public String getPublicId () + { + return publicId; + } + + + /** + * Set the system identifier for this input source. + * + *

The system identifier is optional if there is a byte stream + * or a character stream, but it is still useful to provide one, + * since the application can use it to resolve relative URIs + * and can include it in error messages and warnings (the parser + * will attempt to open a connection to the URI only if + * there is no byte stream or character stream specified).

+ * + *

If the application knows the character encoding of the + * object pointed to by the system identifier, it can register + * the encoding using the setEncoding method.

+ * + *

If the system identifier is a URL, it must be fully + * resolved (it may not be a relative URL).

+ * + * @param systemId The system identifier as a string. + * @see #setEncoding + * @see #getSystemId + * @see org.xml.sax.Locator#getSystemId + * @see org.xml.sax.SAXParseException#getSystemId + */ + public void setSystemId (String systemId) + { + this.systemId = systemId; + } + + + /** + * Get the system identifier for this input source. + * + *

The getEncoding method will return the character encoding + * of the object pointed to, or null if unknown.

+ * + *

If the system ID is a URL, it will be fully resolved.

+ * + * @return The system identifier, or null if none was supplied. + * @see #setSystemId + * @see #getEncoding + */ + public String getSystemId () + { + return systemId; + } + + + /** + * Set the byte stream for this input source. + * + *

The SAX parser will ignore this if there is also a character + * stream specified, but it will use a byte stream in preference + * to opening a URI connection itself.

+ * + *

If the application knows the character encoding of the + * byte stream, it should set it with the setEncoding method.

+ * + * @param byteStream A byte stream containing an XML document or + * other entity. + * @see #setEncoding + * @see #getByteStream + * @see #getEncoding + * @see java.io.InputStream + */ + public void setByteStream (InputStream byteStream) + { + this.byteStream = byteStream; + } + + + /** + * Get the byte stream for this input source. + * + *

The getEncoding method will return the character + * encoding for this byte stream, or null if unknown.

+ * + * @return The byte stream, or null if none was supplied. + * @see #getEncoding + * @see #setByteStream + */ + public InputStream getByteStream () + { + return byteStream; + } + + + /** + * Set the character encoding, if known. + * + *

The encoding must be a string acceptable for an + * XML encoding declaration (see section 4.3.3 of the XML 1.0 + * recommendation).

+ * + *

This method has no effect when the application provides a + * character stream.

+ * + * @param encoding A string describing the character encoding. + * @see #setSystemId + * @see #setByteStream + * @see #getEncoding + */ + public void setEncoding (String encoding) + { + this.encoding = encoding; + } + + + /** + * Get the character encoding for a byte stream or URI. + * This value will be ignored when the application provides a + * character stream. + * + * @return The encoding, or null if none was supplied. + * @see #setByteStream + * @see #getSystemId + * @see #getByteStream + */ + public String getEncoding () + { + return encoding; + } + + + /** + * Set the character stream for this input source. + * + *

If there is a character stream specified, the SAX parser + * will ignore any byte stream and will not attempt to open + * a URI connection to the system identifier.

+ * + * @param characterStream The character stream containing the + * XML document or other entity. + * @see #getCharacterStream + * @see java.io.Reader + */ + public void setCharacterStream (Reader characterStream) + { + this.characterStream = characterStream; + } + + + /** + * Get the character stream for this input source. + * + * @return The character stream, or null if none was supplied. + * @see #setCharacterStream + */ + public Reader getCharacterStream () + { + return characterStream; + } + + + + //////////////////////////////////////////////////////////////////// + // Internal state. + //////////////////////////////////////////////////////////////////// + + private String publicId; + private String systemId; + private InputStream byteStream; + private String encoding; + private Reader characterStream; + +} + +// end of InputSource.java diff --git a/src/org/xml/sax/Locator.java b/src/org/xml/sax/Locator.java new file mode 100644 index 0000000..f8f3484 --- /dev/null +++ b/src/org/xml/sax/Locator.java @@ -0,0 +1,136 @@ +// SAX locator interface for document events. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: Locator.java,v 1.8 2002/01/30 21:13:47 dbrownell Exp $ + +package org.xml.sax; + + +/** + * Interface for associating a SAX event with a document location. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

If a SAX parser provides location information to the SAX + * application, it does so by implementing this interface and then + * passing an instance to the application using the content + * handler's {@link org.xml.sax.ContentHandler#setDocumentLocator + * setDocumentLocator} method. The application can use the + * object to obtain the location of any other SAX event + * in the XML source document.

+ * + *

Note that the results returned by the object will be valid only + * during the scope of each callback method: the application + * will receive unpredictable results if it attempts to use the + * locator at any other time, or after parsing completes.

+ * + *

SAX parsers are not required to supply a locator, but they are + * very strongly encouraged to do so. If the parser supplies a + * locator, it must do so before reporting any other document events. + * If no locator has been set by the time the application receives + * the {@link org.xml.sax.ContentHandler#startDocument startDocument} + * event, the application should assume that a locator is not + * available.

+ * + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.ContentHandler#setDocumentLocator + */ +public interface Locator { + + + /** + * Return the public identifier for the current document event. + * + *

The return value is the public identifier of the document + * entity or of the external parsed entity in which the markup + * triggering the event appears.

+ * + * @return A string containing the public identifier, or + * null if none is available. + * @see #getSystemId + */ + public abstract String getPublicId (); + + + /** + * Return the system identifier for the current document event. + * + *

The return value is the system identifier of the document + * entity or of the external parsed entity in which the markup + * triggering the event appears.

+ * + *

If the system identifier is a URL, the parser must resolve it + * fully before passing it to the application. For example, a file + * name must always be provided as a file:... URL, and other + * kinds of relative URI are also resolved against their bases.

+ * + * @return A string containing the system identifier, or null + * if none is available. + * @see #getPublicId + */ + public abstract String getSystemId (); + + + /** + * Return the line number where the current document event ends. + * Lines are delimited by line ends, which are defined in + * the XML specification. + * + *

Warning: The return value from the method + * is intended only as an approximation for the sake of diagnostics; + * it is not intended to provide sufficient information + * to edit the character content of the original XML document. + * In some cases, these "line" numbers match what would be displayed + * as columns, and in others they may not match the source text + * due to internal entity expansion.

+ * + *

The return value is an approximation of the line number + * in the document entity or external parsed entity where the + * markup triggering the event appears.

+ * + *

If possible, the SAX driver should provide the line position + * of the first character after the text associated with the document + * event. The first line is line 1.

+ * + * @return The line number, or -1 if none is available. + * @see #getColumnNumber + */ + public abstract int getLineNumber (); + + + /** + * Return the column number where the current document event ends. + * This is one-based number of Java char values since + * the last line end. + * + *

Warning: The return value from the method + * is intended only as an approximation for the sake of diagnostics; + * it is not intended to provide sufficient information + * to edit the character content of the original XML document. + * For example, when lines contain combining character sequences, wide + * characters, surrogate pairs, or bi-directional text, the value may + * not correspond to the column in a text editor's display.

+ * + *

The return value is an approximation of the column number + * in the document entity or external parsed entity where the + * markup triggering the event appears.

+ * + *

If possible, the SAX driver should provide the line position + * of the first character after the text associated with the document + * event. The first column in each line is column 1.

+ * + * @return The column number, or -1 if none is available. + * @see #getLineNumber + */ + public abstract int getColumnNumber (); + +} + +// end of Locator.java diff --git a/src/org/xml/sax/Parser.java b/src/org/xml/sax/Parser.java new file mode 100644 index 0000000..734819d --- /dev/null +++ b/src/org/xml/sax/Parser.java @@ -0,0 +1,209 @@ +// SAX parser interface. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: Parser.java,v 1.6 2002/01/30 21:13:47 dbrownell Exp $ + +package org.xml.sax; + +import java.io.IOException; +import java.util.Locale; + + +/** + * Basic interface for SAX (Simple API for XML) parsers. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This was the main event supplier interface for SAX1; it has + * been replaced in SAX2 by {@link org.xml.sax.XMLReader XMLReader}, + * which includes Namespace support and sophisticated configurability + * and extensibility.

+ * + *

All SAX1 parsers must implement this basic interface: it allows + * applications to register handlers for different types of events + * and to initiate a parse from a URI, or a character stream.

+ * + *

All SAX1 parsers must also implement a zero-argument constructor + * (though other constructors are also allowed).

+ * + *

SAX1 parsers are reusable but not re-entrant: the application + * may reuse a parser object (possibly with a different input source) + * once the first parse has completed successfully, but it may not + * invoke the parse() methods recursively within a parse.

+ * + * @deprecated This interface has been replaced by the SAX2 + * {@link org.xml.sax.XMLReader XMLReader} + * interface, which includes Namespace support. + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.EntityResolver + * @see org.xml.sax.DTDHandler + * @see org.xml.sax.DocumentHandler + * @see org.xml.sax.ErrorHandler + * @see org.xml.sax.HandlerBase + * @see org.xml.sax.InputSource + */ +public interface Parser +{ + + /** + * Allow an application to request a locale for errors and warnings. + * + *

SAX parsers are not required to provide localisation for errors + * and warnings; if they cannot support the requested locale, + * however, they must throw a SAX exception. Applications may + * not request a locale change in the middle of a parse.

+ * + * @param locale A Java Locale object. + * @exception org.xml.sax.SAXException Throws an exception + * (using the previous or default locale) if the + * requested locale is not supported. + * @see org.xml.sax.SAXException + * @see org.xml.sax.SAXParseException + */ + public abstract void setLocale (Locale locale) + throws SAXException; + + + /** + * Allow an application to register a custom entity resolver. + * + *

If the application does not register an entity resolver, the + * SAX parser will resolve system identifiers and open connections + * to entities itself (this is the default behaviour implemented in + * HandlerBase).

+ * + *

Applications may register a new or different entity resolver + * in the middle of a parse, and the SAX parser must begin using + * the new resolver immediately.

+ * + * @param resolver The object for resolving entities. + * @see EntityResolver + * @see HandlerBase + */ + public abstract void setEntityResolver (EntityResolver resolver); + + + /** + * Allow an application to register a DTD event handler. + * + *

If the application does not register a DTD handler, all DTD + * events reported by the SAX parser will be silently + * ignored (this is the default behaviour implemented by + * HandlerBase).

+ * + *

Applications may register a new or different + * handler in the middle of a parse, and the SAX parser must + * begin using the new handler immediately.

+ * + * @param handler The DTD handler. + * @see DTDHandler + * @see HandlerBase + */ + public abstract void setDTDHandler (DTDHandler handler); + + + /** + * Allow an application to register a document event handler. + * + *

If the application does not register a document handler, all + * document events reported by the SAX parser will be silently + * ignored (this is the default behaviour implemented by + * HandlerBase).

+ * + *

Applications may register a new or different handler in the + * middle of a parse, and the SAX parser must begin using the new + * handler immediately.

+ * + * @param handler The document handler. + * @see DocumentHandler + * @see HandlerBase + */ + public abstract void setDocumentHandler (DocumentHandler handler); + + + /** + * Allow an application to register an error event handler. + * + *

If the application does not register an error event handler, + * all error events reported by the SAX parser will be silently + * ignored, except for fatalError, which will throw a SAXException + * (this is the default behaviour implemented by HandlerBase).

+ * + *

Applications may register a new or different handler in the + * middle of a parse, and the SAX parser must begin using the new + * handler immediately.

+ * + * @param handler The error handler. + * @see ErrorHandler + * @see SAXException + * @see HandlerBase + */ + public abstract void setErrorHandler (ErrorHandler handler); + + + /** + * Parse an XML document. + * + *

The application can use this method to instruct the SAX parser + * to begin parsing an XML document from any valid input + * source (a character stream, a byte stream, or a URI).

+ * + *

Applications may not invoke this method while a parse is in + * progress (they should create a new Parser instead for each + * additional XML document). Once a parse is complete, an + * application may reuse the same Parser object, possibly with a + * different input source.

+ * + * @param source The input source for the top-level of the + * XML document. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @exception java.io.IOException An IO exception from the parser, + * possibly from a byte stream or character stream + * supplied by the application. + * @see org.xml.sax.InputSource + * @see #parse(java.lang.String) + * @see #setEntityResolver + * @see #setDTDHandler + * @see #setDocumentHandler + * @see #setErrorHandler + */ + public abstract void parse (InputSource source) + throws SAXException, IOException; + + + /** + * Parse an XML document from a system identifier (URI). + * + *

This method is a shortcut for the common case of reading a + * document from a system identifier. It is the exact + * equivalent of the following:

+ * + *
+     * parse(new InputSource(systemId));
+     * 
+ * + *

If the system identifier is a URL, it must be fully resolved + * by the application before it is passed to the parser.

+ * + * @param systemId The system identifier (URI). + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @exception java.io.IOException An IO exception from the parser, + * possibly from a byte stream or character stream + * supplied by the application. + * @see #parse(org.xml.sax.InputSource) + */ + public abstract void parse (String systemId) + throws SAXException, IOException; + +} + +// end of Parser.java diff --git a/src/org/xml/sax/SAXException.java b/src/org/xml/sax/SAXException.java new file mode 100644 index 0000000..70a60ce --- /dev/null +++ b/src/org/xml/sax/SAXException.java @@ -0,0 +1,155 @@ +// SAX exception class. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: SAXException.java,v 1.7 2002/01/30 21:13:48 dbrownell Exp $ + +package org.xml.sax; + +/** + * Encapsulate a general SAX error or warning. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This class can contain basic error or warning information from + * either the XML parser or the application: a parser writer or + * application writer can subclass it to provide additional + * functionality. SAX handlers may throw this exception or + * any exception subclassed from it.

+ * + *

If the application needs to pass through other types of + * exceptions, it must wrap those exceptions in a SAXException + * or an exception derived from a SAXException.

+ * + *

If the parser or application needs to include information about a + * specific location in an XML document, it should use the + * {@link org.xml.sax.SAXParseException SAXParseException} subclass.

+ * + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.SAXParseException + */ +public class SAXException extends Exception { + + + /** + * Create a new SAXException. + */ + public SAXException () + { + super(); + this.exception = null; + } + + + /** + * Create a new SAXException. + * + * @param message The error or warning message. + */ + public SAXException (String message) { + super(message); + this.exception = null; + } + + + /** + * Create a new SAXException wrapping an existing exception. + * + *

The existing exception will be embedded in the new + * one, and its message will become the default message for + * the SAXException.

+ * + * @param e The exception to be wrapped in a SAXException. + */ + public SAXException (Exception e) + { + super(); + this.exception = e; + } + + + /** + * Create a new SAXException from an existing exception. + * + *

The existing exception will be embedded in the new + * one, but the new exception will have its own message.

+ * + * @param message The detail message. + * @param e The exception to be wrapped in a SAXException. + */ + public SAXException (String message, Exception e) + { + super(message); + this.exception = e; + } + + + /** + * Return a detail message for this exception. + * + *

If there is an embedded exception, and if the SAXException + * has no detail message of its own, this method will return + * the detail message from the embedded exception.

+ * + * @return The error or warning message. + */ + @Override + public String getMessage () + { + String message = super.getMessage(); + + if (message == null && exception != null) { + return exception.getMessage(); + } else { + return message; + } + } + + + /** + * Return the embedded exception, if any. + * + * @return The embedded exception, or null if there is none. + */ + public Exception getException () + { + return exception; + } + + + /** + * Override toString to pick up any embedded exception. + * + * @return A string representation of this exception. + */ + @Override + public String toString () + { + if (exception != null) { + return exception.toString(); + } else { + return super.toString(); + } + } + + + + ////////////////////////////////////////////////////////////////////// + // Internal state. + ////////////////////////////////////////////////////////////////////// + + + /** + * @serial The embedded exception if tunnelling, or null. + */ + private Exception exception; + +} + +// end of SAXException.java diff --git a/src/org/xml/sax/SAXNotRecognizedException.java b/src/org/xml/sax/SAXNotRecognizedException.java new file mode 100644 index 0000000..0bb1ded --- /dev/null +++ b/src/org/xml/sax/SAXNotRecognizedException.java @@ -0,0 +1,53 @@ +// SAXNotRecognizedException.java - unrecognized feature or value. +// http://www.saxproject.org +// Written by David Megginson +// NO WARRANTY! This class is in the Public Domain. +// $Id: SAXNotRecognizedException.java,v 1.7 2002/01/30 21:13:48 dbrownell Exp $ + +package org.xml.sax; + + +/** + * Exception class for an unrecognized identifier. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

An XMLReader will throw this exception when it finds an + * unrecognized feature or property identifier; SAX applications and + * extensions may use this class for other, similar purposes.

+ * + * @since SAX 2.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.SAXNotSupportedException + */ +public class SAXNotRecognizedException extends SAXException +{ + + /** + * Default constructor. + */ + public SAXNotRecognizedException () + { + super(); + } + + + /** + * Construct a new exception with the given message. + * + * @param message The text message of the exception. + */ + public SAXNotRecognizedException (String message) + { + super(message); + } + +} + +// end of SAXNotRecognizedException.java diff --git a/src/org/xml/sax/SAXNotSupportedException.java b/src/org/xml/sax/SAXNotSupportedException.java new file mode 100644 index 0000000..9a645a9 --- /dev/null +++ b/src/org/xml/sax/SAXNotSupportedException.java @@ -0,0 +1,53 @@ +// SAXNotSupportedException.java - unsupported feature or value. +// http://www.saxproject.org +// Written by David Megginson +// NO WARRANTY! This class is in the Public Domain. +// $Id: SAXNotSupportedException.java,v 1.7 2002/01/30 21:13:48 dbrownell Exp $ + +package org.xml.sax; + +/** + * Exception class for an unsupported operation. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

An XMLReader will throw this exception when it recognizes a + * feature or property identifier, but cannot perform the requested + * operation (setting a state or value). Other SAX2 applications and + * extensions may use this class for similar purposes.

+ * + * @since SAX 2.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.SAXNotRecognizedException + */ +public class SAXNotSupportedException extends SAXException +{ + + /** + * Construct a new exception with no message. + */ + public SAXNotSupportedException () + { + super(); + } + + + /** + * Construct a new exception with the given message. + * + * @param message The text message of the exception. + */ + public SAXNotSupportedException (String message) + { + super(message); + } + +} + +// end of SAXNotSupportedException.java diff --git a/src/org/xml/sax/SAXParseException.java b/src/org/xml/sax/SAXParseException.java new file mode 100644 index 0000000..1df5e14 --- /dev/null +++ b/src/org/xml/sax/SAXParseException.java @@ -0,0 +1,269 @@ +// SAX exception class. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: SAXParseException.java,v 1.11 2004/04/21 13:05:02 dmegginson Exp $ + +package org.xml.sax; + +/** + * Encapsulate an XML parse error or warning. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This exception may include information for locating the error + * in the original XML document, as if it came from a {@link Locator} + * object. Note that although the application + * will receive a SAXParseException as the argument to the handlers + * in the {@link org.xml.sax.ErrorHandler ErrorHandler} interface, + * the application is not actually required to throw the exception; + * instead, it can simply read the information in it and take a + * different action.

+ * + *

Since this exception is a subclass of {@link org.xml.sax.SAXException + * SAXException}, it inherits the ability to wrap another exception.

+ * + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.SAXException + * @see org.xml.sax.Locator + * @see org.xml.sax.ErrorHandler + */ +public class SAXParseException extends SAXException { + + + ////////////////////////////////////////////////////////////////////// + // Constructors. + ////////////////////////////////////////////////////////////////////// + + + /** + * Create a new SAXParseException from a message and a Locator. + * + *

This constructor is especially useful when an application is + * creating its own exception from within a {@link org.xml.sax.ContentHandler + * ContentHandler} callback.

+ * + * @param message The error or warning message. + * @param locator The locator object for the error or warning (may be + * null). + * @see org.xml.sax.Locator + */ + public SAXParseException (String message, Locator locator) { + super(message); + if (locator != null) { + init(locator.getPublicId(), locator.getSystemId(), + locator.getLineNumber(), locator.getColumnNumber()); + } else { + init(null, null, -1, -1); + } + } + + + /** + * Wrap an existing exception in a SAXParseException. + * + *

This constructor is especially useful when an application is + * creating its own exception from within a {@link org.xml.sax.ContentHandler + * ContentHandler} callback, and needs to wrap an existing exception that is not a + * subclass of {@link org.xml.sax.SAXException SAXException}.

+ * + * @param message The error or warning message, or null to + * use the message from the embedded exception. + * @param locator The locator object for the error or warning (may be + * null). + * @param e Any exception. + * @see org.xml.sax.Locator + */ + public SAXParseException (String message, Locator locator, + Exception e) { + super(message, e); + if (locator != null) { + init(locator.getPublicId(), locator.getSystemId(), + locator.getLineNumber(), locator.getColumnNumber()); + } else { + init(null, null, -1, -1); + } + } + + + /** + * Create a new SAXParseException. + * + *

This constructor is most useful for parser writers.

+ * + *

All parameters except the message are as if + * they were provided by a {@link Locator}. For example, if the + * system identifier is a URL (including relative filename), the + * caller must resolve it fully before creating the exception.

+ * + * + * @param message The error or warning message. + * @param publicId The public identifier of the entity that generated + * the error or warning. + * @param systemId The system identifier of the entity that generated + * the error or warning. + * @param lineNumber The line number of the end of the text that + * caused the error or warning. + * @param columnNumber The column number of the end of the text that + * cause the error or warning. + */ + public SAXParseException (String message, String publicId, String systemId, + int lineNumber, int columnNumber) + { + super(message); + init(publicId, systemId, lineNumber, columnNumber); + } + + + /** + * Create a new SAXParseException with an embedded exception. + * + *

This constructor is most useful for parser writers who + * need to wrap an exception that is not a subclass of + * {@link org.xml.sax.SAXException SAXException}.

+ * + *

All parameters except the message and exception are as if + * they were provided by a {@link Locator}. For example, if the + * system identifier is a URL (including relative filename), the + * caller must resolve it fully before creating the exception.

+ * + * @param message The error or warning message, or null to use + * the message from the embedded exception. + * @param publicId The public identifier of the entity that generated + * the error or warning. + * @param systemId The system identifier of the entity that generated + * the error or warning. + * @param lineNumber The line number of the end of the text that + * caused the error or warning. + * @param columnNumber The column number of the end of the text that + * cause the error or warning. + * @param e Another exception to embed in this one. + */ + public SAXParseException (String message, String publicId, String systemId, + int lineNumber, int columnNumber, Exception e) + { + super(message, e); + init(publicId, systemId, lineNumber, columnNumber); + } + + + /** + * Internal initialization method. + * + * @param publicId The public identifier of the entity which generated the exception, + * or null. + * @param systemId The system identifier of the entity which generated the exception, + * or null. + * @param lineNumber The line number of the error, or -1. + * @param columnNumber The column number of the error, or -1. + */ + private void init (String publicId, String systemId, + int lineNumber, int columnNumber) + { + this.publicId = publicId; + this.systemId = systemId; + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + } + + + /** + * Get the public identifier of the entity where the exception occurred. + * + * @return A string containing the public identifier, or null + * if none is available. + * @see org.xml.sax.Locator#getPublicId + */ + public String getPublicId () + { + return this.publicId; + } + + + /** + * Get the system identifier of the entity where the exception occurred. + * + *

If the system identifier is a URL, it will have been resolved + * fully.

+ * + * @return A string containing the system identifier, or null + * if none is available. + * @see org.xml.sax.Locator#getSystemId + */ + public String getSystemId () + { + return this.systemId; + } + + + /** + * The line number of the end of the text where the exception occurred. + * + *

The first line is line 1.

+ * + * @return An integer representing the line number, or -1 + * if none is available. + * @see org.xml.sax.Locator#getLineNumber + */ + public int getLineNumber () + { + return this.lineNumber; + } + + + /** + * The column number of the end of the text where the exception occurred. + * + *

The first column in a line is position 1.

+ * + * @return An integer representing the column number, or -1 + * if none is available. + * @see org.xml.sax.Locator#getColumnNumber + */ + public int getColumnNumber () + { + return this.columnNumber; + } + + + ////////////////////////////////////////////////////////////////////// + // Internal state. + ////////////////////////////////////////////////////////////////////// + + + /** + * @serial The public identifier, or null. + * @see #getPublicId + */ + private String publicId; + + + /** + * @serial The system identifier, or null. + * @see #getSystemId + */ + private String systemId; + + + /** + * @serial The line number, or -1. + * @see #getLineNumber + */ + private int lineNumber; + + + /** + * @serial The column number, or -1. + * @see #getColumnNumber + */ + private int columnNumber; + +} + +// end of SAXParseException.java diff --git a/src/org/xml/sax/XMLFilter.java b/src/org/xml/sax/XMLFilter.java new file mode 100644 index 0000000..5a399fa --- /dev/null +++ b/src/org/xml/sax/XMLFilter.java @@ -0,0 +1,65 @@ +// XMLFilter.java - filter SAX2 events. +// http://www.saxproject.org +// Written by David Megginson +// NO WARRANTY! This class is in the Public Domain. +// $Id: XMLFilter.java,v 1.6 2002/01/30 21:13:48 dbrownell Exp $ + +package org.xml.sax; + + +/** + * Interface for an XML filter. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

An XML filter is like an XML reader, except that it obtains its + * events from another XML reader rather than a primary source like + * an XML document or database. Filters can modify a stream of + * events as they pass on to the final application.

+ * + *

The XMLFilterImpl helper class provides a convenient base + * for creating SAX2 filters, by passing on all {@link org.xml.sax.EntityResolver + * EntityResolver}, {@link org.xml.sax.DTDHandler DTDHandler}, + * {@link org.xml.sax.ContentHandler ContentHandler} and {@link org.xml.sax.ErrorHandler + * ErrorHandler} events automatically.

+ * + * @since SAX 2.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.helpers.XMLFilterImpl + */ +public interface XMLFilter extends XMLReader +{ + + /** + * Set the parent reader. + * + *

This method allows the application to link the filter to + * a parent reader (which may be another filter). The argument + * may not be null.

+ * + * @param parent The parent reader. + */ + public abstract void setParent (XMLReader parent); + + + /** + * Get the parent reader. + * + *

This method allows the application to query the parent + * reader (which may be another filter). It is generally a + * bad idea to perform any operations on the parent reader + * directly: they should all pass through this filter.

+ * + * @return The parent filter, or null if none has been set. + */ + public abstract XMLReader getParent (); + +} + +// end of XMLFilter.java diff --git a/src/org/xml/sax/XMLReader.java b/src/org/xml/sax/XMLReader.java new file mode 100644 index 0000000..9c150a0 --- /dev/null +++ b/src/org/xml/sax/XMLReader.java @@ -0,0 +1,404 @@ +// XMLReader.java - read an XML document. +// http://www.saxproject.org +// Written by David Megginson +// NO WARRANTY! This class is in the Public Domain. +// $Id: XMLReader.java,v 1.9 2004/04/26 17:34:34 dmegginson Exp $ + +package org.xml.sax; + +import java.io.IOException; + + +/** + * Interface for reading an XML document using callbacks. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

Note: despite its name, this interface does + * not extend the standard Java {@link java.io.Reader Reader} + * interface, because reading XML is a fundamentally different activity + * than reading character data.

+ * + *

XMLReader is the interface that an XML parser's SAX2 driver must + * implement. This interface allows an application to set and + * query features and properties in the parser, to register + * event handlers for document processing, and to initiate + * a document parse.

+ * + *

All SAX interfaces are assumed to be synchronous: the + * {@link #parse parse} methods must not return until parsing + * is complete, and readers must wait for an event-handler callback + * to return before reporting the next event.

+ * + *

This interface replaces the (now deprecated) SAX 1.0 {@link + * org.xml.sax.Parser Parser} interface. The XMLReader interface + * contains two important enhancements over the old Parser + * interface (as well as some minor ones):

+ * + *
    + *
  1. it adds a standard way to query and set features and + * properties; and
  2. + *
  3. it adds Namespace support, which is required for many + * higher-level XML standards.
  4. + *
+ * + *

There are adapters available to convert a SAX1 Parser to + * a SAX2 XMLReader and vice-versa.

+ * + * @since SAX 2.0 + * @author David Megginson + * @version 2.0.1+ (sax2r3pre1) + * @see org.xml.sax.XMLFilter + * @see org.xml.sax.helpers.ParserAdapter + * @see org.xml.sax.helpers.XMLReaderAdapter + */ +public interface XMLReader +{ + + + //////////////////////////////////////////////////////////////////// + // Configuration. + //////////////////////////////////////////////////////////////////// + + + /** + * Look up the value of a feature flag. + * + *

The feature name is any fully-qualified URI. It is + * possible for an XMLReader to recognize a feature name but + * temporarily be unable to return its value. + * Some feature values may be available only in specific + * contexts, such as before, during, or after a parse. + * Also, some feature values may not be programmatically accessible. + * (In the case of an adapter for SAX1 {@link Parser}, there is no + * implementation-independent way to expose whether the underlying + * parser is performing validation, expanding external entities, + * and so forth.)

+ * + *

All XMLReaders are required to recognize the + * http://xml.org/sax/features/namespaces and the + * http://xml.org/sax/features/namespace-prefixes feature names.

+ * + *

Typical usage is something like this:

+ * + *
+     * XMLReader r = new MySAXDriver();
+     *
+     *                         // try to activate validation
+     * try {
+     *   r.setFeature("http://xml.org/sax/features/validation", true);
+     * } catch (SAXException e) {
+     *   System.err.println("Cannot activate validation."); 
+     * }
+     *
+     *                         // register event handlers
+     * r.setContentHandler(new MyContentHandler());
+     * r.setErrorHandler(new MyErrorHandler());
+     *
+     *                         // parse the first document
+     * try {
+     *   r.parse("http://www.foo.com/mydoc.xml");
+     * } catch (IOException e) {
+     *   System.err.println("I/O exception reading XML document");
+     * } catch (SAXException e) {
+     *   System.err.println("XML exception reading document.");
+     * }
+     * 
+ * + *

Implementors are free (and encouraged) to invent their own features, + * using names built on their own URIs.

+ * + * @param name The feature name, which is a fully-qualified URI. + * @return The current value of the feature (true or false). + * @exception org.xml.sax.SAXNotRecognizedException If the feature + * value can't be assigned or retrieved. + * @exception org.xml.sax.SAXNotSupportedException When the + * XMLReader recognizes the feature name but + * cannot determine its value at this time. + * @see #setFeature + */ + public boolean getFeature (String name) + throws SAXNotRecognizedException, SAXNotSupportedException; + + + /** + * Set the value of a feature flag. + * + *

The feature name is any fully-qualified URI. It is + * possible for an XMLReader to expose a feature value but + * to be unable to change the current value. + * Some feature values may be immutable or mutable only + * in specific contexts, such as before, during, or after + * a parse.

+ * + *

All XMLReaders are required to support setting + * http://xml.org/sax/features/namespaces to true and + * http://xml.org/sax/features/namespace-prefixes to false.

+ * + * @param name The feature name, which is a fully-qualified URI. + * @param value The requested value of the feature (true or false). + * @exception org.xml.sax.SAXNotRecognizedException If the feature + * value can't be assigned or retrieved. + * @exception org.xml.sax.SAXNotSupportedException When the + * XMLReader recognizes the feature name but + * cannot set the requested value. + * @see #getFeature + */ + public void setFeature (String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException; + + + /** + * Look up the value of a property. + * + *

The property name is any fully-qualified URI. It is + * possible for an XMLReader to recognize a property name but + * temporarily be unable to return its value. + * Some property values may be available only in specific + * contexts, such as before, during, or after a parse.

+ * + *

XMLReaders are not required to recognize any specific + * property names, though an initial core set is documented for + * SAX2.

+ * + *

Implementors are free (and encouraged) to invent their own properties, + * using names built on their own URIs.

+ * + * @param name The property name, which is a fully-qualified URI. + * @return The current value of the property. + * @exception org.xml.sax.SAXNotRecognizedException If the property + * value can't be assigned or retrieved. + * @exception org.xml.sax.SAXNotSupportedException When the + * XMLReader recognizes the property name but + * cannot determine its value at this time. + * @see #setProperty + */ + public Object getProperty (String name) + throws SAXNotRecognizedException, SAXNotSupportedException; + + + /** + * Set the value of a property. + * + *

The property name is any fully-qualified URI. It is + * possible for an XMLReader to recognize a property name but + * to be unable to change the current value. + * Some property values may be immutable or mutable only + * in specific contexts, such as before, during, or after + * a parse.

+ * + *

XMLReaders are not required to recognize setting + * any specific property names, though a core set is defined by + * SAX2.

+ * + *

This method is also the standard mechanism for setting + * extended handlers.

+ * + * @param name The property name, which is a fully-qualified URI. + * @param value The requested value for the property. + * @exception org.xml.sax.SAXNotRecognizedException If the property + * value can't be assigned or retrieved. + * @exception org.xml.sax.SAXNotSupportedException When the + * XMLReader recognizes the property name but + * cannot set the requested value. + */ + public void setProperty (String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException; + + + + //////////////////////////////////////////////////////////////////// + // Event handlers. + //////////////////////////////////////////////////////////////////// + + + /** + * Allow an application to register an entity resolver. + * + *

If the application does not register an entity resolver, + * the XMLReader will perform its own default resolution.

+ * + *

Applications may register a new or different resolver in the + * middle of a parse, and the SAX parser must begin using the new + * resolver immediately.

+ * + * @param resolver The entity resolver. + * @see #getEntityResolver + */ + public void setEntityResolver (EntityResolver resolver); + + + /** + * Return the current entity resolver. + * + * @return The current entity resolver, or null if none + * has been registered. + * @see #setEntityResolver + */ + public EntityResolver getEntityResolver (); + + + /** + * Allow an application to register a DTD event handler. + * + *

If the application does not register a DTD handler, all DTD + * events reported by the SAX parser will be silently ignored.

+ * + *

Applications may register a new or different handler in the + * middle of a parse, and the SAX parser must begin using the new + * handler immediately.

+ * + * @param handler The DTD handler. + * @see #getDTDHandler + */ + public void setDTDHandler (DTDHandler handler); + + + /** + * Return the current DTD handler. + * + * @return The current DTD handler, or null if none + * has been registered. + * @see #setDTDHandler + */ + public DTDHandler getDTDHandler (); + + + /** + * Allow an application to register a content event handler. + * + *

If the application does not register a content handler, all + * content events reported by the SAX parser will be silently + * ignored.

+ * + *

Applications may register a new or different handler in the + * middle of a parse, and the SAX parser must begin using the new + * handler immediately.

+ * + * @param handler The content handler. + * @see #getContentHandler + */ + public void setContentHandler (ContentHandler handler); + + + /** + * Return the current content handler. + * + * @return The current content handler, or null if none + * has been registered. + * @see #setContentHandler + */ + public ContentHandler getContentHandler (); + + + /** + * Allow an application to register an error event handler. + * + *

If the application does not register an error handler, all + * error events reported by the SAX parser will be silently + * ignored; however, normal processing may not continue. It is + * highly recommended that all SAX applications implement an + * error handler to avoid unexpected bugs.

+ * + *

Applications may register a new or different handler in the + * middle of a parse, and the SAX parser must begin using the new + * handler immediately.

+ * + * @param handler The error handler. + * @see #getErrorHandler + */ + public void setErrorHandler (ErrorHandler handler); + + + /** + * Return the current error handler. + * + * @return The current error handler, or null if none + * has been registered. + * @see #setErrorHandler + */ + public ErrorHandler getErrorHandler (); + + + + //////////////////////////////////////////////////////////////////// + // Parsing. + //////////////////////////////////////////////////////////////////// + + /** + * Parse an XML document. + * + *

The application can use this method to instruct the XML + * reader to begin parsing an XML document from any valid input + * source (a character stream, a byte stream, or a URI).

+ * + *

Applications may not invoke this method while a parse is in + * progress (they should create a new XMLReader instead for each + * nested XML document). Once a parse is complete, an + * application may reuse the same XMLReader object, possibly with a + * different input source. + * Configuration of the XMLReader object (such as handler bindings and + * values established for feature flags and properties) is unchanged + * by completion of a parse, unless the definition of that aspect of + * the configuration explicitly specifies other behavior. + * (For example, feature flags or properties exposing + * characteristics of the document being parsed.) + *

+ * + *

During the parse, the XMLReader will provide information + * about the XML document through the registered event + * handlers.

+ * + *

This method is synchronous: it will not return until parsing + * has ended. If a client application wants to terminate + * parsing early, it should throw an exception.

+ * + * @param input The input source for the top-level of the + * XML document. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @exception java.io.IOException An IO exception from the parser, + * possibly from a byte stream or character stream + * supplied by the application. + * @see org.xml.sax.InputSource + * @see #parse(java.lang.String) + * @see #setEntityResolver + * @see #setDTDHandler + * @see #setContentHandler + * @see #setErrorHandler + */ + public void parse (InputSource input) + throws IOException, SAXException; + + + /** + * Parse an XML document from a system identifier (URI). + * + *

This method is a shortcut for the common case of reading a + * document from a system identifier. It is the exact + * equivalent of the following:

+ * + *
+     * parse(new InputSource(systemId));
+     * 
+ * + *

If the system identifier is a URL, it must be fully resolved + * by the application before it is passed to the parser.

+ * + * @param systemId The system identifier (URI). + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @exception java.io.IOException An IO exception from the parser, + * possibly from a byte stream or character stream + * supplied by the application. + * @see #parse(org.xml.sax.InputSource) + */ + public void parse (String systemId) + throws IOException, SAXException; + +} diff --git a/src/org/xml/sax/demo/ByteStreamDemo.java b/src/org/xml/sax/demo/ByteStreamDemo.java new file mode 100644 index 0000000..5da34b9 --- /dev/null +++ b/src/org/xml/sax/demo/ByteStreamDemo.java @@ -0,0 +1,78 @@ +package org.xml.sax.demo; +// SAX demonstration for parsing from a raw byte stream. +// No warranty; no copyright -- use this as you will. +// $Id: ByteStreamDemo.java,v 1.4 1998/05/01 20:38:19 david Exp $ + +import org.xml.sax.Parser; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import org.xml.sax.helpers.ParserFactory; + +import java.io.FileInputStream; + + + +/** + * Demonstrate parsing from a byte stream. + * + *

Usage: java -Dorg.xml.sax.parser=CLASSNAME ByteStreamDemo + * FILE

+ * + *

The SAX parser will open a byte stream to the file name + * provided. Note the use of the InputStreamAdapter class to allow a + * Java InputStream to serve as a SAX ByteStream.

+ * + * @see DemoHandler + */ +public class ByteStreamDemo { + + + /** + * Main entry point. + */ + public static void main (String args[]) + throws Exception + { + Parser parser; + InputSource source; + DemoHandler handler; + FileInputStream input; + + // First, check the command-line usage. + if (args.length != 1) { + System.err.println("Usage: java -Dorg.xml.sax.parser= " + + "SystemIdDemo "); + System.exit(2); + } + + // Allocate a SAX Parser object, using + // the class name provided in the + // org.xml.sax.parser property. + parser = ParserFactory.makeParser(); + + // Allocate an event handler, and register + // it with the SAX parser for all four + // types of events (we could use a + // separate object for each). + handler = new DemoHandler(); + parser.setEntityResolver(handler); + parser.setDTDHandler(handler); + parser.setDocumentHandler(handler); + parser.setErrorHandler(handler); + + // Create a Java FileInputStream from + // the file: note that SAX cannot + // use this directly. + input = new FileInputStream(args[0]); + + // Create the input source. + source = new InputSource(input); + source.setSystemId(args[0]); + + // Parse the document from the + // ByteStream. + parser.parse(source); + } + +} diff --git a/src/org/xml/sax/demo/CharacterStreamDemo.java b/src/org/xml/sax/demo/CharacterStreamDemo.java new file mode 100644 index 0000000..8d97f0f --- /dev/null +++ b/src/org/xml/sax/demo/CharacterStreamDemo.java @@ -0,0 +1,88 @@ +package org.xml.sax.demo; +// SAX demonstration for parsing from a UTF-16 character stream. +// No warranty; no copyright -- use this as you will. +// $Id: CharacterStreamDemo.java,v 1.3 1998/05/01 20:44:33 david Exp $ + +import org.xml.sax.Parser; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import org.xml.sax.helpers.ParserFactory; + +import java.io.StringReader; + + +/** + * Demonstrate parsing from a UTF-16 character stream. + * + *

Usage: java -Dorg.xml.sax.parser=CLASSNAME + * CharacterStreamDemo

+ * + *

The SAX parser will read the document from a character + * stream connected to an internal string.

+ * + *

Note that the Java implementation of SAX represents a + * character stream using a Reader.

+ * + * @see DemoHandler + * @see org.xml.org.xml.sax.parser + * @see org.xml.sax.InputSource + * @see org.xml.sax.helpers.ParserFactory + * @see java.io.StringReader + */ +public class CharacterStreamDemo { + + // This is the document, in all its glory. + // In a read-world application, this + // could come from a database, a text + // field, or just about anywhere. + final static String doc = "" + + "\n" + + "Hello\n" + + "Hello, world!\n" + + "\n"; + + /** + * Main entry point for an application. + */ + public static void main (String args[]) + throws Exception + { + DemoHandler handler; + InputSource source; + Parser parser; + StringReader reader; + + // First, check the command-line + // arguments. + if (args.length != 0) { + System.err.println("Usage: java CharTest"); + System.exit(2); + } + + // Allocate a SAX Parser object, using + // the class name provided in the + // org.xml.sax.parser property (you could + // also specify a classname here). + parser = ParserFactory.makeParser(); + + // Allocate an event handler, and register + // it with the SAX parser for all four + // types of events (we could use a + // separate object for each). + handler = new DemoHandler(); + parser.setEntityResolver(handler); + parser.setDTDHandler(handler); + parser.setDocumentHandler(handler); + parser.setErrorHandler(handler); + + // Create a Java-specific StringReader + // for the internal document. + reader = new StringReader(doc); + + // Parse the document from the + // character stream. + parser.parse(new InputSource(reader)); + } + +} diff --git a/src/org/xml/sax/demo/DemoHandler.java b/src/org/xml/sax/demo/DemoHandler.java new file mode 100644 index 0000000..66c6a08 --- /dev/null +++ b/src/org/xml/sax/demo/DemoHandler.java @@ -0,0 +1,325 @@ +package org.xml.sax.demo; + +// SAX event handler for demos. +// No warranty; no copyright -- use this as you will. +// $Id: DemoHandler.java,v 1.3 1998/05/01 20:45:16 david Exp $ + +import org.xml.sax.HandlerBase; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.AttributeList; +import org.xml.sax.EntityResolver; +import org.xml.sax.DTDHandler; +import org.xml.sax.DocumentHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXParseException; + + +/** + * Event handler class for SAX demos. + * + *

This handler simply reports all of the events that it receives. + * It is useful for testing and comparing SAX implementations, and + * for teaching or learning about SAX. This is also a demonstration + * of how one class can implement all four handler interfaces.

+ * + * @see org.xml.sax.EntityResolver + * @see org.xml.sax.DTDHandler + * @see org.xml.sax.DocumentHandler + * @see org.xml.sax.ErrorHandler + */ +public class DemoHandler + implements EntityResolver, DTDHandler, DocumentHandler, ErrorHandler +{ + + + + ////////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.EntityResolver + ////////////////////////////////////////////////////////////////////// + + + /** + * Display requests for entity resolution. + * + *

The SAX parser will invoke this method to give the application + * a chance to resolve entities. This implementation always + * returns null, so that the parser will resolve the entity + * itself.

+ * + * @see org.xml.sax.EntityResolver#resolveEntity + */ + @Override + public InputSource resolveEntity (String publicId, String systemId) + { + System.out.print("Resolve entity:"); + if (publicId != null) { + System.out.print(" publicId=\"" + publicId + '"'); + } + System.out.println(" systemId=\"" + systemId + '"'); + + return null; + } + + + + ////////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.DTDHandler + ////////////////////////////////////////////////////////////////////// + + + /** + * Display notation declarations as they are reported. + * + * @see org.xml.sax.DTDHandler#notationDecl + */ + @Override + public void notationDecl (String name, String publicId, String systemId) + { + System.out.print("Notation declaration: " + name); + if (publicId != null) { + System.out.print(" publicId=\"" + publicId + '"'); + } + if (systemId != null) { + System.out.print(" systemId=\"" + systemId + '"'); + } + System.out.print('\n'); + } + + + /** + * Display unparsed entity declarations as they are reported. + * + * @see org.xml.sax.DTDHandler#unparsedEntityDecl + */ + @Override + public void unparsedEntityDecl (String name, + String publicId, + String systemId, + String notationName) + { + System.out.print("Unparsed Entity Declaration: " + name); + if (publicId != null) { + System.out.print(" publicId=\"" + publicId + '"'); + } + if (systemId != null) { + System.out.print(" systemId=\"" + systemId + '"'); + } + System.out.println(" notationName=\"" + notationName + '"'); + } + + + + ////////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.DocumentHandler + ////////////////////////////////////////////////////////////////////// + + + /** + * Print a message when the parser provides a locator. + * + *

Not all SAX parsers will provide a locator object.

+ * + * @see org.xml.sax.DocumentHandler#setDocumentLocator + */ + @Override + public void setDocumentLocator (Locator locator) + { + System.out.println("Document locator supplied."); + } + + + /** + * Print a message at the start of the document. + * + * @see org.xml.sax.DocumentHandler#startDocument + */ + @Override + public void startDocument () + { + System.out.println("Start document"); + } + + + /** + * Print a message for the end of the document. + * + * @see org.xml.sax.DocumentHandler#endDocument + */ + @Override + public void endDocument () + { + System.out.println("End document"); + } + + + /** + * Print a message for the start of an element. + * + *

Display all attributes on separate lines, indented.

+ * + * @see org.xml.sax.DocumentHandler#startElement + */ + @Override + public void startElement (String name, AttributeList attributes) + { + System.out.println("Start element: " + name); + for (int i = 0; i < attributes.getLength(); i++) { + System.out.println(" Attribute: " + + attributes.getName(i) + + ' ' + + attributes.getType(i) + + " \"" + + attributes.getValue(i) + + '"'); + } + } + + + /** + * Print a message for the end of an element. + * + * @see org.xml.sax.DocumentHandler#endElement + */ + @Override + public void endElement (String name) + { + System.out.println("End element: " + name); + } + + + /** + * Print a message for character data. + * + * @see org.xml.sax.DocumentHandler#characters + */ + @Override + public void characters (char ch[], int start, int length) + { + System.out.print("Characters: "); + display(ch, start, length); + } + + + /** + * Print a message for ignorable whitespace. + * + * @see org.xml.sax.DocumentHandler#ignorableWhitespace + */ + @Override + public void ignorableWhitespace (char ch[], int start, int length) + { + System.out.print("Ignorable Whitespace: "); + display(ch, start, length); + } + + + /** + * Print a message for a processing instruction. + * + * @see org.xml.sax.DocumentHandler#processingInstruction + */ + @Override + public void processingInstruction (String target, String data) + { + System.out.println("Processing instruction: " + target + ' ' + data); + } + + + + ////////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.ErrorHandler + ////////////////////////////////////////////////////////////////////// + + + /** + * Report all warnings, and continue parsing. + * + * @see org.xml.sax.ErrorHandler#warning + */ + @Override + public void warning (SAXParseException exception) + { + System.out.println("Warning: " + + exception.getMessage() + + " (" + + exception.getSystemId() + + ':' + + exception.getLineNumber() + + ',' + + exception.getColumnNumber() + + ')'); + } + + + /** + * Report all recoverable errors, and try to continue parsing. + * + * @see org.xml.sax.ErrorHandler#error + */ + @Override + public void error (SAXParseException exception) + { + System.out.println("Recoverable Error: " + + exception.getMessage() + + " (" + + exception.getSystemId() + + ':' + + exception.getLineNumber() + + ',' + + exception.getColumnNumber() + + ')'); + } + + + /** + * Report all fatal errors, and try to continue parsing. + * + *

Note: results are no longer reliable once a fatal error has + * been reported.

+ * + * @see org.xml.sax.ErrorHandler#fatalError + */ + @Override + public void fatalError (SAXParseException exception) + { + System.out.println("Fatal Error: " + + exception.getMessage() + + " (" + + exception.getSystemId() + + ':' + + exception.getLineNumber() + + ',' + + exception.getColumnNumber() + + ')'); + } + + + + ////////////////////////////////////////////////////////////////////// + // Utility routines. + ////////////////////////////////////////////////////////////////////// + + + /** + * Display text, escaping some characters. + */ + private static void display (char ch[], int start, int length) + { + for (int i = start; i < start + length; i++) { + switch (ch[i]) { + case '\n': + System.out.print("\\n"); + break; + case '\t': + System.out.print("\\t"); + break; + default: + System.out.print(ch[i]); + break; + } + } + System.out.print("\n"); + } + +} diff --git a/src/org/xml/sax/demo/EntityDemo.java b/src/org/xml/sax/demo/EntityDemo.java new file mode 100644 index 0000000..be3948c --- /dev/null +++ b/src/org/xml/sax/demo/EntityDemo.java @@ -0,0 +1,128 @@ +package org.xml.sax.demo; +// SAX demonstration for custom entity resolution. +// No warranty; no copyright -- use this as you will. +// $Id: EntityDemo.java,v 1.2 1998/05/01 20:52:16 david Exp $ + +import org.xml.sax.InputSource; +import org.xml.sax.Parser; +import org.xml.sax.SAXException; + +import org.xml.sax.helpers.ParserFactory; + +import java.io.StringReader; +import java.net.URL; + + +/** + * Demonstrate custom entity resolution. + * + *

Usage: java -Dorg.xml.sax.parser=classname EntityDemo + * systemId

+ * + *

If you create an XML document which references an + * external text entity with the public identifier + * "-//megginson//TEXT Sample Entity//EN", this application will + * substitute the string "Entity resolution works!" for the + * entity's contents:

+ * + *
+  * <!DOCTYPE doc [
+  *   <!ENTITY ent 
+  *     PUBLIC "-//megginson//TEXT Sample Entity//EN" "ent.xml">
+  * ]>
+  * <doc>
+  * <para>&ent;</para>
+  * </doc>
+  * 
+ * + *

The SAX parser will open a connection to the URI itself.

+ * + * @see DemoHandler + */ +public class EntityDemo extends DemoHandler { + + // This is the Reader that will be + // substituted for the entity contents. + StringReader reader = + new StringReader("Entity resolution works!"); + + /** + * Main entry point. + */ + public static void main (String args[]) + throws Exception + { + Parser parser; + EntityDemo handler; + + // Check the command-line usage. + if (args.length != 1) { + System.err.println("Usage: java -Dorg.xml.sax.parser= " + + "EntityDemo "); + System.exit(2); + } + + // Make the parser, using the value + // provided in the org.xml.sax.parser property. + parser = ParserFactory.makeParser(); + + // Create an event handler, and register + // it with the SAX parser. + handler = new EntityDemo(); + parser.setEntityResolver(handler); + parser.setDTDHandler(handler); + parser.setDocumentHandler(handler); + parser.setErrorHandler(handler); + + // Parse the document. + parser.parse(makeAbsoluteURL(args[0])); + } + + + /** + * Override resolveEntity(). + * + *

If the public identifier is "-//megginson//TEXT Sample + * //Entity//EN", instruct the parser to read the entity's + * contents from the StringReader rather than from the + * system identifier.

+ * + *

The public identifier is safer than the system identifier, + * since the parser may have resolved the system identifier to + * an absolute URL.

+ * + * @see org.xml.sax.EntityResolver#resolveEntity + */ + @Override + public InputSource resolveEntity (String publicId, String systemId) + { + if (publicId != null && + publicId.equals("-//megginson//TEXT Sample Entity//EN")) { + return new InputSource(reader); + } else { + return null; + } + } + + + /** + * If a URL is relative, make it absolute against the current directory. + */ + private static String makeAbsoluteURL (String url) + throws java.net.MalformedURLException + { + URL baseURL; + + String currentDirectory = System.getProperty("user.dir"); + String fileSep = System.getProperty("file.separator"); + String file = currentDirectory.replace(fileSep.charAt(0), '/') + '/'; + + if (file.charAt(0) != '/') { + file = "/" + file; + } + baseURL = new URL("file", null, file); + + return new URL(baseURL, url).toString(); + } + +} diff --git a/src/org/xml/sax/ext/Attributes2.java b/src/org/xml/sax/ext/Attributes2.java new file mode 100644 index 0000000..cb1d679 --- /dev/null +++ b/src/org/xml/sax/ext/Attributes2.java @@ -0,0 +1,132 @@ +// Attributes2.java - extended Attributes +// http://www.saxproject.org +// Public Domain: no warranty. +// $Id: Attributes2.java,v 1.6 2004/03/08 13:01:00 dmegginson Exp $ + +package org.xml.sax.ext; + +import org.xml.sax.Attributes; + + +/** + * SAX2 extension to augment the per-attribute information + * provided though {@link Attributes}. + * If an implementation supports this extension, the attributes + * provided in {@link org.xml.sax.ContentHandler#startElement + * ContentHandler.startElement() } will implement this interface, + * and the http://xml.org/sax/features/use-attributes2 + * feature flag will have the value true. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + *
+ * + *

XMLReader implementations are not required to support this + * information, and it is not part of core-only SAX2 distributions.

+ * + *

Note that if an attribute was defaulted (!isSpecified()) + * it will of necessity also have been declared (isDeclared()) + * in the DTD. + * Similarly if an attribute's type is anything except CDATA, then it + * must have been declared. + *

+ * + * @since SAX 2.0 (extensions 1.1 alpha) + * @author David Brownell + * @version TBS + */ +public interface Attributes2 extends Attributes +{ + /** + * Returns false unless the attribute was declared in the DTD. + * This helps distinguish two kinds of attributes that SAX reports + * as CDATA: ones that were declared (and hence are usually valid), + * and those that were not (and which are never valid). + * + * @param index The attribute index (zero-based). + * @return true if the attribute was declared in the DTD, + * false otherwise. + * @exception java.lang.ArrayIndexOutOfBoundsException When the + * supplied index does not identify an attribute. + */ + public boolean isDeclared (int index); + + /** + * Returns false unless the attribute was declared in the DTD. + * This helps distinguish two kinds of attributes that SAX reports + * as CDATA: ones that were declared (and hence are usually valid), + * and those that were not (and which are never valid). + * + * @param qName The XML qualified (prefixed) name. + * @return true if the attribute was declared in the DTD, + * false otherwise. + * @exception java.lang.IllegalArgumentException When the + * supplied name does not identify an attribute. + */ + public boolean isDeclared (String qName); + + /** + * Returns false unless the attribute was declared in the DTD. + * This helps distinguish two kinds of attributes that SAX reports + * as CDATA: ones that were declared (and hence are usually valid), + * and those that were not (and which are never valid). + * + *

Remember that since DTDs do not "understand" namespaces, the + * namespace URI associated with an attribute may not have come from + * the DTD. The declaration will have applied to the attribute's + * qName. + * + * @param uri The Namespace URI, or the empty string if + * the name has no Namespace URI. + * @param localName The attribute's local name. + * @return true if the attribute was declared in the DTD, + * false otherwise. + * @exception java.lang.IllegalArgumentException When the + * supplied names do not identify an attribute. + */ + public boolean isDeclared (String uri, String localName); + + /** + * Returns true unless the attribute value was provided + * by DTD defaulting. + * + * @param index The attribute index (zero-based). + * @return true if the value was found in the XML text, + * false if the value was provided by DTD defaulting. + * @exception java.lang.ArrayIndexOutOfBoundsException When the + * supplied index does not identify an attribute. + */ + public boolean isSpecified (int index); + + /** + * Returns true unless the attribute value was provided + * by DTD defaulting. + * + *

Remember that since DTDs do not "understand" namespaces, the + * namespace URI associated with an attribute may not have come from + * the DTD. The declaration will have applied to the attribute's + * qName. + * + * @param uri The Namespace URI, or the empty string if + * the name has no Namespace URI. + * @param localName The attribute's local name. + * @return true if the value was found in the XML text, + * false if the value was provided by DTD defaulting. + * @exception java.lang.IllegalArgumentException When the + * supplied names do not identify an attribute. + */ + public boolean isSpecified (String uri, String localName); + + /** + * Returns true unless the attribute value was provided + * by DTD defaulting. + * + * @param qName The XML qualified (prefixed) name. + * @return true if the value was found in the XML text, + * false if the value was provided by DTD defaulting. + * @exception java.lang.IllegalArgumentException When the + * supplied name does not identify an attribute. + */ + public boolean isSpecified (String qName); +} diff --git a/src/org/xml/sax/ext/Attributes2Impl.java b/src/org/xml/sax/ext/Attributes2Impl.java new file mode 100644 index 0000000..ad24c78 --- /dev/null +++ b/src/org/xml/sax/ext/Attributes2Impl.java @@ -0,0 +1,310 @@ +// Attributes2Impl.java - extended AttributesImpl +// http://www.saxproject.org +// Public Domain: no warranty. +// $Id: Attributes2Impl.java,v 1.5 2004/03/08 13:01:01 dmegginson Exp $ + +package org.xml.sax.ext; + +import org.xml.sax.Attributes; +import org.xml.sax.helpers.AttributesImpl; + + +/** + * SAX2 extension helper for additional Attributes information, + * implementing the {@link Attributes2} interface. + * + *

+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + *
+ * + *

This is not part of core-only SAX2 distributions.

+ * + *

The specified flag for each attribute will always + * be true, unless it has been set to false in the copy constructor + * or using {@link #setSpecified}. + * Similarly, the declared flag for each attribute will + * always be false, except for defaulted attributes (specified + * is false), non-CDATA attributes, or when it is set to true using + * {@link #setDeclared}. + * If you change an attribute's type by hand, you may need to modify + * its declared flag to match. + *

+ * + * @since SAX 2.0 (extensions 1.1 alpha) + * @author David Brownell + * @version TBS + */ +public class Attributes2Impl extends AttributesImpl implements Attributes2 +{ + private boolean declared []; + private boolean specified []; + + + /** + * Construct a new, empty Attributes2Impl object. + */ + public Attributes2Impl () { } + + + /** + * Copy an existing Attributes or Attributes2 object. + * If the object implements Attributes2, values of the + * specified and declared flags for each + * attribute are copied. + * Otherwise the flag values are defaulted to assume no DTD was used, + * unless there is evidence to the contrary (such as attributes with + * type other than CDATA, which must have been declared). + * + *

This constructor is especially useful inside a + * {@link org.xml.sax.ContentHandler#startElement startElement} event.

+ * + * @param atts The existing Attributes object. + */ + public Attributes2Impl (Attributes atts) + { + super (atts); + } + + + //////////////////////////////////////////////////////////////////// + // Implementation of Attributes2 + //////////////////////////////////////////////////////////////////// + + + /** + * Returns the current value of the attribute's "declared" flag. + */ + // javadoc mostly from interface + @Override + public boolean isDeclared (int index) + { + if (index < 0 || index >= getLength ()) + throw new ArrayIndexOutOfBoundsException ( + "No attribute at index: " + index); + return declared [index]; + } + + + /** + * Returns the current value of the attribute's "declared" flag. + */ + // javadoc mostly from interface + @Override + public boolean isDeclared (String uri, String localName) + { + int index = getIndex (uri, localName); + + if (index < 0) + throw new IllegalArgumentException ( + "No such attribute: local=" + localName + + ", namespace=" + uri); + return declared [index]; + } + + + /** + * Returns the current value of the attribute's "declared" flag. + */ + // javadoc mostly from interface + @Override + public boolean isDeclared (String qName) + { + int index = getIndex (qName); + + if (index < 0) + throw new IllegalArgumentException ( + "No such attribute: " + qName); + return declared [index]; + } + + + /** + * Returns the current value of an attribute's "specified" flag. + * + * @param index The attribute index (zero-based). + * @return current flag value + * @exception java.lang.ArrayIndexOutOfBoundsException When the + * supplied index does not identify an attribute. + */ + @Override + public boolean isSpecified (int index) + { + if (index < 0 || index >= getLength ()) + throw new ArrayIndexOutOfBoundsException ( + "No attribute at index: " + index); + return specified [index]; + } + + + /** + * Returns the current value of an attribute's "specified" flag. + * + * @param uri The Namespace URI, or the empty string if + * the name has no Namespace URI. + * @param localName The attribute's local name. + * @return current flag value + * @exception java.lang.IllegalArgumentException When the + * supplied names do not identify an attribute. + */ + @Override + public boolean isSpecified (String uri, String localName) + { + int index = getIndex (uri, localName); + + if (index < 0) + throw new IllegalArgumentException ( + "No such attribute: local=" + localName + + ", namespace=" + uri); + return specified [index]; + } + + + /** + * Returns the current value of an attribute's "specified" flag. + * + * @param qName The XML qualified (prefixed) name. + * @return current flag value + * @exception java.lang.IllegalArgumentException When the + * supplied name does not identify an attribute. + */ + @Override + public boolean isSpecified (String qName) + { + int index = getIndex (qName); + + if (index < 0) + throw new IllegalArgumentException ( + "No such attribute: " + qName); + return specified [index]; + } + + + //////////////////////////////////////////////////////////////////// + // Manipulators + //////////////////////////////////////////////////////////////////// + + + /** + * Copy an entire Attributes object. The "specified" flags are + * assigned as true, and "declared" flags as false (except when + * an attribute's type is not CDATA), + * unless the object is an Attributes2 object. + * In that case those flag values are all copied. + * + * @see AttributesImpl#setAttributes + */ + @Override + public void setAttributes (Attributes atts) + { + int length = atts.getLength (); + + super.setAttributes (atts); + declared = new boolean [length]; + specified = new boolean [length]; + + if (atts instanceof Attributes2) { + Attributes2 a2 = (Attributes2) atts; + for (int i = 0; i < length; i++) { + declared [i] = a2.isDeclared (i); + specified [i] = a2.isSpecified (i); + } + } else { + for (int i = 0; i < length; i++) { + declared [i] = !"CDATA".equals (atts.getType (i)); + specified [i] = true; + } + } + } + + + /** + * Add an attribute to the end of the list, setting its + * "specified" flag to true. To set that flag's value + * to false, use {@link #setSpecified}. + * + *

Unless the attribute type is CDATA, this attribute + * is marked as being declared in the DTD. To set that flag's value + * to true for CDATA attributes, use {@link #setDeclared}. + * + * @see AttributesImpl#addAttribute + */ + @Override + public void addAttribute (String uri, String localName, String qName, + String type, String value) + { + super.addAttribute (uri, localName, qName, type, value); + + int length = getLength (); + + if (length < specified.length) { + boolean newFlags []; + + newFlags = new boolean [length]; + System.arraycopy (declared, 0, newFlags, 0, declared.length); + declared = newFlags; + + newFlags = new boolean [length]; + System.arraycopy (specified, 0, newFlags, 0, specified.length); + specified = newFlags; + } + + specified [length - 1] = true; + declared [length - 1] = !"CDATA".equals (type); + } + + + // javadoc entirely from superclass + @Override + public void removeAttribute (int index) + { + int origMax = getLength () - 1; + + super.removeAttribute (index); + if (index != origMax) { + System.arraycopy (declared, index + 1, declared, index, + origMax - index); + System.arraycopy (specified, index + 1, specified, index, + origMax - index); + } + } + + + /** + * Assign a value to the "declared" flag of a specific attribute. + * This is normally needed only for attributes of type CDATA, + * including attributes whose type is changed to or from CDATA. + * + * @param index The index of the attribute (zero-based). + * @param value The desired flag value. + * @exception java.lang.ArrayIndexOutOfBoundsException When the + * supplied index does not identify an attribute. + * @see #setType + */ + public void setDeclared (int index, boolean value) + { + if (index < 0 || index >= getLength ()) + throw new ArrayIndexOutOfBoundsException ( + "No attribute at index: " + index); + declared [index] = value; + } + + + /** + * Assign a value to the "specified" flag of a specific attribute. + * This is the only way this flag can be cleared, except clearing + * by initialization with the copy constructor. + * + * @param index The index of the attribute (zero-based). + * @param value The desired flag value. + * @exception java.lang.ArrayIndexOutOfBoundsException When the + * supplied index does not identify an attribute. + */ + public void setSpecified (int index, boolean value) + { + if (index < 0 || index >= getLength ()) + throw new ArrayIndexOutOfBoundsException ( + "No attribute at index: " + index); + specified [index] = value; + } +} diff --git a/src/org/xml/sax/ext/DeclHandler.java b/src/org/xml/sax/ext/DeclHandler.java new file mode 100644 index 0000000..865e33c --- /dev/null +++ b/src/org/xml/sax/ext/DeclHandler.java @@ -0,0 +1,146 @@ +// DeclHandler.java - Optional handler for DTD declaration events. +// http://www.saxproject.org +// Public Domain: no warranty. +// $Id: DeclHandler.java,v 1.6 2004/04/22 13:28:49 dmegginson Exp $ + +package org.xml.sax.ext; + +import org.xml.sax.SAXException; + + +/** + * SAX2 extension handler for DTD declaration events. + * + *

+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This is an optional extension handler for SAX2 to provide more + * complete information about DTD declarations in an XML document. + * XML readers are not required to recognize this handler, and it + * is not part of core-only SAX2 distributions.

+ * + *

Note that data-related DTD declarations (unparsed entities and + * notations) are already reported through the {@link + * org.xml.sax.DTDHandler DTDHandler} interface.

+ * + *

If you are using the declaration handler together with a lexical + * handler, all of the events will occur between the + * {@link org.xml.sax.ext.LexicalHandler#startDTD startDTD} and the + * {@link org.xml.sax.ext.LexicalHandler#endDTD endDTD} events.

+ * + *

To set the DeclHandler for an XML reader, use the + * {@link org.xml.sax.XMLReader#setProperty setProperty} method + * with the property name + * http://xml.org/sax/properties/declaration-handler + * and an object implementing this interface (or null) as the value. + * If the reader does not report declaration events, it will throw a + * {@link org.xml.sax.SAXNotRecognizedException SAXNotRecognizedException} + * when you attempt to register the handler.

+ * + * @since SAX 2.0 (extensions 1.0) + * @author David Megginson + * @version 2.0.1 (sax2r2) + */ +public interface DeclHandler +{ + + /** + * Report an element type declaration. + * + *

The content model will consist of the string "EMPTY", the + * string "ANY", or a parenthesised group, optionally followed + * by an occurrence indicator. The model will be normalized so + * that all parameter entities are fully resolved and all whitespace + * is removed,and will include the enclosing parentheses. Other + * normalization (such as removing redundant parentheses or + * simplifying occurrence indicators) is at the discretion of the + * parser.

+ * + * @param name The element type name. + * @param model The content model as a normalized string. + * @exception SAXException The application may raise an exception. + */ + public abstract void elementDecl (String name, String model) + throws SAXException; + + + /** + * Report an attribute type declaration. + * + *

Only the effective (first) declaration for an attribute will + * be reported. The type will be one of the strings "CDATA", + * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", + * "ENTITIES", a parenthesized token group with + * the separator "|" and all whitespace removed, or the word + * "NOTATION" followed by a space followed by a parenthesized + * token group with all whitespace removed.

+ * + *

The value will be the value as reported to applications, + * appropriately normalized and with entity and character + * references expanded.

+ * + * @param eName The name of the associated element. + * @param aName The name of the attribute. + * @param type A string representing the attribute type. + * @param mode A string representing the attribute defaulting mode + * ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if + * none of these applies. + * @param value A string representing the attribute's default value, + * or null if there is none. + * @exception SAXException The application may raise an exception. + */ + public abstract void attributeDecl (String eName, + String aName, + String type, + String mode, + String value) + throws SAXException; + + + /** + * Report an internal entity declaration. + * + *

Only the effective (first) declaration for each entity + * will be reported. All parameter entities in the value + * will be expanded, but general entities will not.

+ * + * @param name The name of the entity. If it is a parameter + * entity, the name will begin with '%'. + * @param value The replacement text of the entity. + * @exception SAXException The application may raise an exception. + * @see #externalEntityDecl + * @see org.xml.sax.DTDHandler#unparsedEntityDecl + */ + public abstract void internalEntityDecl (String name, String value) + throws SAXException; + + + /** + * Report a parsed external entity declaration. + * + *

Only the effective (first) declaration for each entity + * will be reported.

+ * + *

If the system identifier is a URL, the parser must resolve it + * fully before passing it to the application.

+ * + * @param name The name of the entity. If it is a parameter + * entity, the name will begin with '%'. + * @param publicId The entity's public identifier, or null if none + * was given. + * @param systemId The entity's system identifier. + * @exception SAXException The application may raise an exception. + * @see #internalEntityDecl + * @see org.xml.sax.DTDHandler#unparsedEntityDecl + */ + public abstract void externalEntityDecl (String name, String publicId, + String systemId) + throws SAXException; + +} + +// end of DeclHandler.java diff --git a/src/org/xml/sax/ext/DefaultHandler2.java b/src/org/xml/sax/ext/DefaultHandler2.java new file mode 100644 index 0000000..f2096ad --- /dev/null +++ b/src/org/xml/sax/ext/DefaultHandler2.java @@ -0,0 +1,144 @@ +// DefaultHandler2.java - extended DefaultHandler +// http://www.saxproject.org +// Public Domain: no warranty. +// $Id: DefaultHandler2.java,v 1.3 2002/01/12 19:04:19 dbrownell Exp $ + +package org.xml.sax.ext; + +import java.io.IOException; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + + +/** + * This class extends the SAX2 base handler class to support the + * SAX2 {@link LexicalHandler}, {@link DeclHandler}, and + * {@link EntityResolver2} extensions. Except for overriding the + * original SAX1 {@link DefaultHandler#resolveEntity resolveEntity()} + * method the added handler methods just return. Subclassers may + * override everything on a method-by-method basis. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + *
+ * + *

Note: this class might yet learn that the + * ContentHandler.setDocumentLocator() call might be passed a + * {@link Locator2} object, and that the + * ContentHandler.startElement() call might be passed a + * {@link Attributes2} object. + * + * @since SAX 2.0 (extensions 1.1 alpha) + * @author David Brownell + * @version TBS + */ +public class DefaultHandler2 extends DefaultHandler + implements LexicalHandler, DeclHandler, EntityResolver2 +{ + /** Constructs a handler which ignores all parsing events. */ + public DefaultHandler2 () { } + + + // SAX2 ext-1.0 LexicalHandler + + @Override + public void startCDATA () + throws SAXException + {} + + @Override + public void endCDATA () + throws SAXException + {} + + @Override + public void startDTD (String name, String publicId, String systemId) + throws SAXException + {} + + @Override + public void endDTD () + throws SAXException + {} + + @Override + public void startEntity (String name) + throws SAXException + {} + + @Override + public void endEntity (String name) + throws SAXException + {} + + @Override + public void comment (char ch [], int start, int length) + throws SAXException + { } + + + // SAX2 ext-1.0 DeclHandler + + @Override + public void attributeDecl (String eName, String aName, + String type, String mode, String value) + throws SAXException + {} + + @Override + public void elementDecl (String name, String model) + throws SAXException + {} + + @Override + public void externalEntityDecl (String name, + String publicId, String systemId) + throws SAXException + {} + + @Override + public void internalEntityDecl (String name, String value) + throws SAXException + {} + + // SAX2 ext-1.1 EntityResolver2 + + /** + * Tells the parser that if no external subset has been declared + * in the document text, none should be used. + */ + @Override + public InputSource getExternalSubset (String name, String baseURI) + throws SAXException, IOException + { return null; } + + /** + * Tells the parser to resolve the systemId against the baseURI + * and read the entity text from that resulting absolute URI. + * Note that because the older + * {@link DefaultHandler#resolveEntity DefaultHandler.resolveEntity()}, + * method is overridden to call this one, this method may sometimes + * be invoked with null name and baseURI, and + * with the systemId already absolutized. + */ + @Override + public InputSource resolveEntity (String name, String publicId, + String baseURI, String systemId) + throws SAXException, IOException + { return null; } + + // SAX1 EntityResolver + + /** + * Invokes + * {@link EntityResolver2#resolveEntity EntityResolver2.resolveEntity()} + * with null entity name and base URI. + * You only need to override that method to use this class. + */ + @Override + public InputSource resolveEntity (String publicId, String systemId) + throws SAXException, IOException + { return resolveEntity (null, publicId, null, systemId); } +} diff --git a/src/org/xml/sax/ext/EntityResolver2.java b/src/org/xml/sax/ext/EntityResolver2.java new file mode 100644 index 0000000..a1108a3 --- /dev/null +++ b/src/org/xml/sax/ext/EntityResolver2.java @@ -0,0 +1,197 @@ +// EntityResolver2.java - Extended SAX entity resolver. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: EntityResolver2.java,v 1.2 2002/01/12 19:20:08 dbrownell Exp $ + +package org.xml.sax.ext; + +import java.io.IOException; + +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import org.xml.sax.SAXException; + + +/** + * Extended interface for mapping external entity references to input + * sources, or providing a missing external subset. The + * {@link XMLReader#setEntityResolver XMLReader.setEntityResolver()} method + * is used to provide implementations of this interface to parsers. + * When a parser uses the methods in this interface, the + * {@link EntityResolver2#resolveEntity EntityResolver2.resolveEntity()} + * method (in this interface) is used instead of the older (SAX 1.0) + * {@link EntityResolver#resolveEntity EntityResolver.resolveEntity()} method. + * + *

+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + *
+ * + *

If a SAX application requires the customized handling which this + * interface defines for external entities, it must ensure that it uses + * an XMLReader with the + * http://xml.org/sax/features/use-entity-resolver2 feature flag + * set to true (which is its default value when the feature is + * recognized). If that flag is unrecognized, or its value is false, + * or the resolver does not implement this interface, then only the + * {@link EntityResolver} method will be used. + *

+ * + *

That supports three categories of application that modify entity + * resolution. Old Style applications won't know about this interface; + * they will provide an EntityResolver. + * Transitional Mode provide an EntityResolver2 and automatically + * get the benefit of its methods in any systems (parsers or other tools) + * supporting it, due to polymorphism. + * Both Old Style and Transitional Mode applications will + * work with any SAX2 parser. + * New style applications will fail to run except on SAX2 parsers + * that support this particular feature. + * They will insist that feature flag have a value of "true", and the + * EntityResolver2 implementation they provide might throw an exception + * if the original SAX 1.0 style entity resolution method is invoked. + *

+ * + * @see org.xml.sax.XMLReader#setEntityResolver + * + * @since SAX 2.0 (extensions 1.1 alpha) + * @author David Brownell + * @version TBD + */ +public interface EntityResolver2 extends EntityResolver +{ + /** + * Allows applications to provide an external subset for documents + * that don't explicitly define one. Documents with DOCTYPE declarations + * that omit an external subset can thus augment the declarations + * available for validation, entity processing, and attribute processing + * (normalization, defaulting, and reporting types including ID). + * This augmentation is reported + * through the {@link LexicalHandler#startDTD startDTD()} method as if + * the document text had originally included the external subset; + * this callback is made before any internal subset data or errors + * are reported.

+ * + *

This method can also be used with documents that have no DOCTYPE + * declaration. When the root element is encountered, + * but no DOCTYPE declaration has been seen, this method is + * invoked. If it returns a value for the external subset, that root + * element is declared to be the root element, giving the effect of + * splicing a DOCTYPE declaration at the end the prolog of a document + * that could not otherwise be valid. The sequence of parser callbacks + * in that case logically resembles this:

+ * + *
+     * ... comments and PIs from the prolog (as usual)
+     * startDTD ("rootName", source.getPublicId (), source.getSystemId ());
+     * startEntity ("[dtd]");
+     * ... declarations, comments, and PIs from the external subset
+     * endEntity ("[dtd]");
+     * endDTD ();
+     * ... then the rest of the document (as usual)
+     * startElement (..., "rootName", ...);
+     * 
+ * + *

Note that the InputSource gets no further resolution. + * Implementations of this method may wish to invoke + * {@link #resolveEntity resolveEntity()} to gain benefits such as use + * of local caches of DTD entities. Also, this method will never be + * used by a (non-validating) processor that is not including external + * parameter entities.

+ * + *

Uses for this method include facilitating data validation when + * interoperating with XML processors that would always require + * undesirable network accesses for external entities, or which for + * other reasons adopt a "no DTDs" policy. + * Non-validation motives include forcing documents to include DTDs so + * that attributes are handled consistently. + * For example, an XPath processor needs to know which attibutes have + * type "ID" before it can process a widely used type of reference.

+ * + *

Warning: Returning an external subset modifies + * the input document. By providing definitions for general entities, + * it can make a malformed document appear to be well formed. + *

+ * + * @param name Identifies the document root element. This name comes + * from a DOCTYPE declaration (where available) or from the actual + * root element. + * @param baseURI The document's base URI, serving as an additional + * hint for selecting the external subset. This is always an absolute + * URI, unless it is null because the XMLReader was given an InputSource + * without one. + * + * @return An InputSource object describing the new external subset + * to be used by the parser, or null to indicate that no external + * subset is provided. + * + * @exception SAXException Any SAX exception, possibly wrapping + * another exception. + * @exception IOException Probably indicating a failure to create + * a new InputStream or Reader, or an illegal URL. + */ + public InputSource getExternalSubset (String name, String baseURI) + throws SAXException, IOException; + + /** + * Allows applications to map references to external entities into input + * sources, or tell the parser it should use conventional URI resolution. + * This method is only called for external entities which have been + * properly declared. + * This method provides more flexibility than the {@link EntityResolver} + * interface, supporting implementations of more complex catalogue + * schemes such as the one defined by the OASIS XML Catalogs specification.

+ * + *

Parsers configured to use this resolver method will call it + * to determine the input source to use for any external entity + * being included because of a reference in the XML text. + * That excludes the document entity, and any external entity returned + * by {@link #getExternalSubset getExternalSubset()}. + * When a (non-validating) processor is configured not to include + * a class of entities (parameter or general) through use of feature + * flags, this method is not invoked for such entities.

+ * + *

Note that the entity naming scheme used here is the same one + * used in the {@link LexicalHandler}, or in the {@link + org.xml.sax.ContentHandler#skippedEntity + ContentHandler.skippedEntity()} + * method.

+ * + * @param name Identifies the external entity being resolved. + * Either "[dtd]" for the external subset, or a name starting + * with "%" to indicate a parameter entity, or else the name of + * a general entity. This is never null when invoked by a SAX2 + * parser. + * @param publicId The public identifier of the external entity being + * referenced (normalized as required by the XML specification), or + * null if none was supplied. + * @param baseURI The URI with respect to which relative systemIDs + * are interpreted. This is always an absolute URI, unless it is + * null (likely because the XMLReader was given an InputSource without + * one). This URI is defined by the XML specification to be the one + * associated with the "<" starting the relevant declaration. + * @param systemId The system identifier of the external entity + * being referenced; either a relative or absolute URI. + * This is never null when invoked by a SAX2 parser; only declared + * entities, and any external subset, are resolved by such parsers. + * + * @return An InputSource object describing the new input source to + * be used by the parser. Returning null directs the parser to + * resolve the system ID against the base URI and open a connection + * to resulting URI. + * + * @exception SAXException Any SAX exception, possibly wrapping + * another exception. + * @exception IOException Probably indicating a failure to create + * a new InputStream or Reader, or an illegal URL. + */ + public InputSource resolveEntity ( + String name, + String publicId, + String baseURI, + String systemId + ) throws SAXException, IOException; +} diff --git a/src/org/xml/sax/ext/LexicalHandler.java b/src/org/xml/sax/ext/LexicalHandler.java new file mode 100644 index 0000000..d63d87f --- /dev/null +++ b/src/org/xml/sax/ext/LexicalHandler.java @@ -0,0 +1,212 @@ +// LexicalHandler.java - optional handler for lexical parse events. +// http://www.saxproject.org +// Public Domain: no warranty. +// $Id: LexicalHandler.java,v 1.5 2002/01/30 21:00:44 dbrownell Exp $ + +package org.xml.sax.ext; + +import org.xml.sax.SAXException; + +/** + * SAX2 extension handler for lexical events. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This is an optional extension handler for SAX2 to provide + * lexical information about an XML document, such as comments + * and CDATA section boundaries. + * XML readers are not required to recognize this handler, and it + * is not part of core-only SAX2 distributions.

+ * + *

The events in the lexical handler apply to the entire document, + * not just to the document element, and all lexical handler events + * must appear between the content handler's startDocument and + * endDocument events.

+ * + *

To set the LexicalHandler for an XML reader, use the + * {@link org.xml.sax.XMLReader#setProperty setProperty} method + * with the property name + * http://xml.org/sax/properties/lexical-handler + * and an object implementing this interface (or null) as the value. + * If the reader does not report lexical events, it will throw a + * {@link org.xml.sax.SAXNotRecognizedException SAXNotRecognizedException} + * when you attempt to register the handler.

+ * + * @since SAX 2.0 (extensions 1.0) + * @author David Megginson + * @version 2.0.1 (sax2r2) + */ +public interface LexicalHandler +{ + + /** + * Report the start of DTD declarations, if any. + * + *

This method is intended to report the beginning of the + * DOCTYPE declaration; if the document has no DOCTYPE declaration, + * this method will not be invoked.

+ * + *

All declarations reported through + * {@link org.xml.sax.DTDHandler DTDHandler} or + * {@link org.xml.sax.ext.DeclHandler DeclHandler} events must appear + * between the startDTD and {@link #endDTD endDTD} events. + * Declarations are assumed to belong to the internal DTD subset + * unless they appear between {@link #startEntity startEntity} + * and {@link #endEntity endEntity} events. Comments and + * processing instructions from the DTD should also be reported + * between the startDTD and endDTD events, in their original + * order of (logical) occurrence; they are not required to + * appear in their correct locations relative to DTDHandler + * or DeclHandler events, however.

+ * + *

Note that the start/endDTD events will appear within + * the start/endDocument events from ContentHandler and + * before the first + * {@link org.xml.sax.ContentHandler#startElement startElement} + * event.

+ * + * @param name The document type name. + * @param publicId The declared public identifier for the + * external DTD subset, or null if none was declared. + * @param systemId The declared system identifier for the + * external DTD subset, or null if none was declared. + * (Note that this is not resolved against the document + * base URI.) + * @exception SAXException The application may raise an + * exception. + * @see #endDTD + * @see #startEntity + */ + public abstract void startDTD (String name, String publicId, + String systemId) + throws SAXException; + + + /** + * Report the end of DTD declarations. + * + *

This method is intended to report the end of the + * DOCTYPE declaration; if the document has no DOCTYPE declaration, + * this method will not be invoked.

+ * + * @exception SAXException The application may raise an exception. + * @see #startDTD + */ + public abstract void endDTD () + throws SAXException; + + + /** + * Report the beginning of some internal and external XML entities. + * + *

The reporting of parameter entities (including + * the external DTD subset) is optional, and SAX2 drivers that + * report LexicalHandler events may not implement it; you can use the + * http://xml.org/sax/features/lexical-handler/parameter-entities + * feature to query or control the reporting of parameter entities.

+ * + *

General entities are reported with their regular names, + * parameter entities have '%' prepended to their names, and + * the external DTD subset has the pseudo-entity name "[dtd]".

+ * + *

When a SAX2 driver is providing these events, all other + * events must be properly nested within start/end entity + * events. There is no additional requirement that events from + * {@link org.xml.sax.ext.DeclHandler DeclHandler} or + * {@link org.xml.sax.DTDHandler DTDHandler} be properly ordered.

+ * + *

Note that skipped entities will be reported through the + * {@link org.xml.sax.ContentHandler#skippedEntity skippedEntity} + * event, which is part of the ContentHandler interface.

+ * + *

Because of the streaming event model that SAX uses, some + * entity boundaries cannot be reported under any + * circumstances:

+ * + *
    + *
  • general entities within attribute values
  • + *
  • parameter entities within declarations
  • + *
+ * + *

These will be silently expanded, with no indication of where + * the original entity boundaries were.

+ * + *

Note also that the boundaries of character references (which + * are not really entities anyway) are not reported.

+ * + *

All start/endEntity events must be properly nested. + * + * @param name The name of the entity. If it is a parameter + * entity, the name will begin with '%', and if it is the + * external DTD subset, it will be "[dtd]". + * @exception SAXException The application may raise an exception. + * @see #endEntity + * @see org.xml.sax.ext.DeclHandler#internalEntityDecl + * @see org.xml.sax.ext.DeclHandler#externalEntityDecl + */ + public abstract void startEntity (String name) + throws SAXException; + + + /** + * Report the end of an entity. + * + * @param name The name of the entity that is ending. + * @exception SAXException The application may raise an exception. + * @see #startEntity + */ + public abstract void endEntity (String name) + throws SAXException; + + + /** + * Report the start of a CDATA section. + * + *

The contents of the CDATA section will be reported through + * the regular {@link org.xml.sax.ContentHandler#characters + * characters} event; this event is intended only to report + * the boundary.

+ * + * @exception SAXException The application may raise an exception. + * @see #endCDATA + */ + public abstract void startCDATA () + throws SAXException; + + + /** + * Report the end of a CDATA section. + * + * @exception SAXException The application may raise an exception. + * @see #startCDATA + */ + public abstract void endCDATA () + throws SAXException; + + + /** + * Report an XML comment anywhere in the document. + * + *

This callback will be used for comments inside or outside the + * document element, including comments in the external DTD + * subset (if read). Comments in the DTD must be properly + * nested inside start/endDTD and start/endEntity events (if + * used).

+ * + * @param ch An array holding the characters in the comment. + * @param start The starting position in the array. + * @param length The number of characters to use from the array. + * @exception SAXException The application may raise an exception. + */ + public abstract void comment (char ch[], int start, int length) + throws SAXException; + +} + +// end of LexicalHandler.java diff --git a/src/org/xml/sax/ext/Locator2.java b/src/org/xml/sax/ext/Locator2.java new file mode 100644 index 0000000..6de9a16 --- /dev/null +++ b/src/org/xml/sax/ext/Locator2.java @@ -0,0 +1,75 @@ +// Locator2.java - extended Locator +// http://www.saxproject.org +// Public Domain: no warranty. +// $Id: Locator2.java,v 1.5 2004/03/17 14:30:10 dmegginson Exp $ + +package org.xml.sax.ext; + +import org.xml.sax.Locator; + + +/** + * SAX2 extension to augment the entity information provided + * though a {@link Locator}. + * If an implementation supports this extension, the Locator + * provided in {@link org.xml.sax.ContentHandler#setDocumentLocator + * ContentHandler.setDocumentLocator() } will implement this + * interface, and the + * http://xml.org/sax/features/use-locator2 feature + * flag will have the value true. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + *
+ * + *

XMLReader implementations are not required to support this + * information, and it is not part of core-only SAX2 distributions.

+ * + * @since SAX 2.0 (extensions 1.1 alpha) + * @author David Brownell + * @version TBS + */ +public interface Locator2 extends Locator +{ + /** + * Returns the version of XML used for the entity. This will + * normally be the identifier from the current entity's + * <?xml version='...' ...?> declaration, + * or be defaulted by the parser. + * + * @return Identifier for the XML version being used to interpret + * the entity's text, or null if that information is not yet + * available in the current parsing state. + */ + public String getXMLVersion (); + + /** + * Returns the name of the character encoding for the entity. + * If the encoding was declared externally (for example, in a MIME + * Content-Type header), that will be the name returned. Else if there + * was an <?xml ...encoding='...'?> declaration at + * the start of the document, that encoding name will be returned. + * Otherwise the encoding will been inferred (normally to be UTF-8, or + * some UTF-16 variant), and that inferred name will be returned. + * + *

When an {@link org.xml.sax.InputSource InputSource} is used + * to provide an entity's character stream, this method returns the + * encoding provided in that input stream. + * + *

Note that some recent W3C specifications require that text + * in some encodings be normalized, using Unicode Normalization + * Form C, before processing. Such normalization must be performed + * by applications, and would normally be triggered based on the + * value returned by this method. + * + *

Encoding names may be those used by the underlying JVM, + * and comparisons should be case-insensitive. + * + * @return Name of the character encoding being used to interpret + * * the entity's text, or null if this was not provided for a * + * character stream passed through an InputSource or is otherwise + * not yet available in the current parsing state. + */ + public String getEncoding (); +} diff --git a/src/org/xml/sax/ext/Locator2Impl.java b/src/org/xml/sax/ext/Locator2Impl.java new file mode 100644 index 0000000..89ea4ba --- /dev/null +++ b/src/org/xml/sax/ext/Locator2Impl.java @@ -0,0 +1,103 @@ +// Locator2Impl.java - extended LocatorImpl +// http://www.saxproject.org +// Public Domain: no warranty. +// $Id: Locator2Impl.java,v 1.3 2004/04/26 17:34:35 dmegginson Exp $ + +package org.xml.sax.ext; + +import org.xml.sax.Locator; +import org.xml.sax.helpers.LocatorImpl; + + +/** + * SAX2 extension helper for holding additional Entity information, + * implementing the {@link Locator2} interface. + * + *

+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + *
+ * + *

This is not part of core-only SAX2 distributions.

+ * + * @since SAX 2.0.2 + * @author David Brownell + * @version TBS + */ +public class Locator2Impl extends LocatorImpl implements Locator2 +{ + private String encoding; + private String version; + + + /** + * Construct a new, empty Locator2Impl object. + * This will not normally be useful, since the main purpose + * of this class is to make a snapshot of an existing Locator. + */ + public Locator2Impl () { } + + /** + * Copy an existing Locator or Locator2 object. + * If the object implements Locator2, values of the + * encoding and versionstrings are copied, + * otherwise they set to null. + * + * @param locator The existing Locator object. + */ + public Locator2Impl (Locator locator) + { + super (locator); + if (locator instanceof Locator2) { + Locator2 l2 = (Locator2) locator; + + version = l2.getXMLVersion (); + encoding = l2.getEncoding (); + } + } + + //////////////////////////////////////////////////////////////////// + // Locator2 method implementations + //////////////////////////////////////////////////////////////////// + + /** + * Returns the current value of the version property. + * + * @see #setXMLVersion + */ + @Override + public String getXMLVersion () + { return version; } + + /** + * Returns the current value of the encoding property. + * + * @see #setEncoding + */ + @Override + public String getEncoding () + { return encoding; } + + + //////////////////////////////////////////////////////////////////// + // Setters + //////////////////////////////////////////////////////////////////// + + /** + * Assigns the current value of the version property. + * + * @param version the new "version" value + * @see #getXMLVersion + */ + public void setXMLVersion (String version) + { this.version = version; } + + /** + * Assigns the current value of the encoding property. + * + * @param encoding the new "encoding" value + * @see #getEncoding + */ + public void setEncoding (String encoding) + { this.encoding = encoding; } +} diff --git a/src/org/xml/sax/helpers/AttributeListImpl.java b/src/org/xml/sax/helpers/AttributeListImpl.java new file mode 100644 index 0000000..fba22ea --- /dev/null +++ b/src/org/xml/sax/helpers/AttributeListImpl.java @@ -0,0 +1,318 @@ +// SAX default implementation for AttributeList. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: AttributeListImpl.java,v 1.6 2002/01/30 20:52:22 dbrownell Exp $ + +package org.xml.sax.helpers; + +import org.xml.sax.AttributeList; + +import java.util.Vector; + + +/**e + * Default implementation for AttributeList. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

AttributeList implements the deprecated SAX1 {@link + * org.xml.sax.AttributeList AttributeList} interface, and has been + * replaced by the new SAX2 {@link org.xml.sax.helpers.AttributesImpl + * AttributesImpl} interface.

+ * + *

This class provides a convenience implementation of the SAX + * {@link org.xml.sax.AttributeList AttributeList} interface. This + * implementation is useful both for SAX parser writers, who can use + * it to provide attributes to the application, and for SAX application + * writers, who can use it to create a persistent copy of an element's + * attribute specifications:

+ * + *
+ * private AttributeList myatts;
+ *
+ * public void startElement (String name, AttributeList atts)
+ * {
+ *              // create a persistent copy of the attribute list
+ *              // for use outside this method
+ *   myatts = new AttributeListImpl(atts);
+ *   [...]
+ * }
+ * 
+ * + *

Please note that SAX parsers are not required to use this + * class to provide an implementation of AttributeList; it is + * supplied only as an optional convenience. In particular, + * parser writers are encouraged to invent more efficient + * implementations.

+ * + * @deprecated This class implements a deprecated interface, + * {@link org.xml.sax.AttributeList AttributeList}; + * that interface has been replaced by + * {@link org.xml.sax.Attributes Attributes}, + * which is implemented in the + * {@link org.xml.sax.helpers.AttributesImpl + * AttributesImpl} helper class. + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.AttributeList + * @see org.xml.sax.DocumentHandler#startElement + */ +public class AttributeListImpl implements AttributeList +{ + + /** + * Create an empty attribute list. + * + *

This constructor is most useful for parser writers, who + * will use it to create a single, reusable attribute list that + * can be reset with the clear method between elements.

+ * + * @see #addAttribute + * @see #clear + */ + public AttributeListImpl () + { + } + + + /** + * Construct a persistent copy of an existing attribute list. + * + *

This constructor is most useful for application writers, + * who will use it to create a persistent copy of an existing + * attribute list.

+ * + * @param atts The attribute list to copy + * @see org.xml.sax.DocumentHandler#startElement + */ + public AttributeListImpl (AttributeList atts) + { + setAttributeList(atts); + } + + + + //////////////////////////////////////////////////////////////////// + // Methods specific to this class. + //////////////////////////////////////////////////////////////////// + + + /** + * Set the attribute list, discarding previous contents. + * + *

This method allows an application writer to reuse an + * attribute list easily.

+ * + * @param atts The attribute list to copy. + */ + public void setAttributeList (AttributeList atts) + { + int count = atts.getLength(); + + clear(); + + for (int i = 0; i < count; i++) { + addAttribute(atts.getName(i), atts.getType(i), atts.getValue(i)); + } + } + + + /** + * Add an attribute to an attribute list. + * + *

This method is provided for SAX parser writers, to allow them + * to build up an attribute list incrementally before delivering + * it to the application.

+ * + * @param name The attribute name. + * @param type The attribute type ("NMTOKEN" for an enumeration). + * @param value The attribute value (must not be null). + * @see #removeAttribute + * @see org.xml.sax.DocumentHandler#startElement + */ + public void addAttribute (String name, String type, String value) + { + names.addElement(name); + types.addElement(type); + values.addElement(value); + } + + + /** + * Remove an attribute from the list. + * + *

SAX application writers can use this method to filter an + * attribute out of an AttributeList. Note that invoking this + * method will change the length of the attribute list and + * some of the attribute's indices.

+ * + *

If the requested attribute is not in the list, this is + * a no-op.

+ * + * @param name The attribute name. + * @see #addAttribute + */ + public void removeAttribute (String name) + { + int i = names.indexOf(name); + + if (i >= 0) { + names.removeElementAt(i); + types.removeElementAt(i); + values.removeElementAt(i); + } + } + + + /** + * Clear the attribute list. + * + *

SAX parser writers can use this method to reset the attribute + * list between DocumentHandler.startElement events. Normally, + * it will make sense to reuse the same AttributeListImpl object + * rather than allocating a new one each time.

+ * + * @see org.xml.sax.DocumentHandler#startElement + */ + public void clear () + { + names.removeAllElements(); + types.removeAllElements(); + values.removeAllElements(); + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.AttributeList + //////////////////////////////////////////////////////////////////// + + + /** + * Return the number of attributes in the list. + * + * @return The number of attributes in the list. + * @see org.xml.sax.AttributeList#getLength + */ + @Override + public int getLength () + { + return names.size(); + } + + + /** + * Get the name of an attribute (by position). + * + * @param i The position of the attribute in the list. + * @return The attribute name as a string, or null if there + * is no attribute at that position. + * @see org.xml.sax.AttributeList#getName(int) + */ + @Override + public String getName (int i) + { + if (i < 0) { + return null; + } + try { + return (String)names.elementAt(i); + } catch (ArrayIndexOutOfBoundsException e) { + return null; + } + } + + + /** + * Get the type of an attribute (by position). + * + * @param i The position of the attribute in the list. + * @return The attribute type as a string ("NMTOKEN" for an + * enumeration, and "CDATA" if no declaration was + * read), or null if there is no attribute at + * that position. + * @see org.xml.sax.AttributeList#getType(int) + */ + @Override + public String getType (int i) + { + if (i < 0) { + return null; + } + try { + return (String)types.elementAt(i); + } catch (ArrayIndexOutOfBoundsException e) { + return null; + } + } + + + /** + * Get the value of an attribute (by position). + * + * @param i The position of the attribute in the list. + * @return The attribute value as a string, or null if + * there is no attribute at that position. + * @see org.xml.sax.AttributeList#getValue(int) + */ + @Override + public String getValue (int i) + { + if (i < 0) { + return null; + } + try { + return (String)values.elementAt(i); + } catch (ArrayIndexOutOfBoundsException e) { + return null; + } + } + + + /** + * Get the type of an attribute (by name). + * + * @param name The attribute name. + * @return The attribute type as a string ("NMTOKEN" for an + * enumeration, and "CDATA" if no declaration was + * read). + * @see org.xml.sax.AttributeList#getType(java.lang.String) + */ + @Override + public String getType (String name) + { + return getType(names.indexOf(name)); + } + + + /** + * Get the value of an attribute (by name). + * + * @param name The attribute name. + * @see org.xml.sax.AttributeList#getValue(java.lang.String) + */ + @Override + public String getValue (String name) + { + return getValue(names.indexOf(name)); + } + + + + //////////////////////////////////////////////////////////////////// + // Internal state. + //////////////////////////////////////////////////////////////////// + + Vector names = new Vector(); + Vector types = new Vector(); + Vector values = new Vector(); + +} + +// end of AttributeListImpl.java diff --git a/src/org/xml/sax/helpers/AttributesImpl.java b/src/org/xml/sax/helpers/AttributesImpl.java new file mode 100644 index 0000000..fac6b26 --- /dev/null +++ b/src/org/xml/sax/helpers/AttributesImpl.java @@ -0,0 +1,630 @@ +// AttributesImpl.java - default implementation of Attributes. +// http://www.saxproject.org +// Written by David Megginson +// NO WARRANTY! This class is in the public domain. +// $Id: AttributesImpl.java,v 1.9 2002/01/30 20:52:24 dbrownell Exp $ + +package org.xml.sax.helpers; + +import org.xml.sax.Attributes; + + +/** + * Default implementation of the Attributes interface. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This class provides a default implementation of the SAX2 + * {@link org.xml.sax.Attributes Attributes} interface, with the + * addition of manipulators so that the list can be modified or + * reused.

+ * + *

There are two typical uses of this class:

+ * + *
    + *
  1. to take a persistent snapshot of an Attributes object + * in a {@link org.xml.sax.ContentHandler#startElement startElement} event; or
  2. + *
  3. to construct or modify an Attributes object in a SAX2 driver or filter.
  4. + *
+ * + *

This class replaces the now-deprecated SAX1 {@link + * org.xml.sax.helpers.AttributeListImpl AttributeListImpl} + * class; in addition to supporting the updated Attributes + * interface rather than the deprecated {@link org.xml.sax.AttributeList + * AttributeList} interface, it also includes a much more efficient + * implementation using a single array rather than a set of Vectors.

+ * + * @since SAX 2.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + */ +public class AttributesImpl implements Attributes +{ + + + //////////////////////////////////////////////////////////////////// + // Constructors. + //////////////////////////////////////////////////////////////////// + + + /** + * Construct a new, empty AttributesImpl object. + */ + public AttributesImpl () + { + length = 0; + data = null; + } + + + /** + * Copy an existing Attributes object. + * + *

This constructor is especially useful inside a + * {@link org.xml.sax.ContentHandler#startElement startElement} event.

+ * + * @param atts The existing Attributes object. + */ + public AttributesImpl (Attributes atts) + { + setAttributes(atts); + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.Attributes. + //////////////////////////////////////////////////////////////////// + + + /** + * Return the number of attributes in the list. + * + * @return The number of attributes in the list. + * @see org.xml.sax.Attributes#getLength + */ + @Override + public int getLength () + { + return length; + } + + + /** + * Return an attribute's Namespace URI. + * + * @param index The attribute's index (zero-based). + * @return The Namespace URI, the empty string if none is + * available, or null if the index is out of range. + * @see org.xml.sax.Attributes#getURI + */ + @Override + public String getURI (int index) + { + if (index >= 0 && index < length) { + return data[index*5]; + } else { + return null; + } + } + + + /** + * Return an attribute's local name. + * + * @param index The attribute's index (zero-based). + * @return The attribute's local name, the empty string if + * none is available, or null if the index if out of range. + * @see org.xml.sax.Attributes#getLocalName + */ + @Override + public String getLocalName (int index) + { + if (index >= 0 && index < length) { + return data[index*5+1]; + } else { + return null; + } + } + + + /** + * Return an attribute's qualified (prefixed) name. + * + * @param index The attribute's index (zero-based). + * @return The attribute's qualified name, the empty string if + * none is available, or null if the index is out of bounds. + * @see org.xml.sax.Attributes#getQName + */ + @Override + public String getQName (int index) + { + if (index >= 0 && index < length) { + return data[index*5+2]; + } else { + return null; + } + } + + + /** + * Return an attribute's type by index. + * + * @param index The attribute's index (zero-based). + * @return The attribute's type, "CDATA" if the type is unknown, or null + * if the index is out of bounds. + * @see org.xml.sax.Attributes#getType(int) + */ + @Override + public String getType (int index) + { + if (index >= 0 && index < length) { + return data[index*5+3]; + } else { + return null; + } + } + + + /** + * Return an attribute's value by index. + * + * @param index The attribute's index (zero-based). + * @return The attribute's value or null if the index is out of bounds. + * @see org.xml.sax.Attributes#getValue(int) + */ + @Override + public String getValue (int index) + { + if (index >= 0 && index < length) { + return data[index*5+4]; + } else { + return null; + } + } + + + /** + * Look up an attribute's index by Namespace name. + * + *

In many cases, it will be more efficient to look up the name once and + * use the index query methods rather than using the name query methods + * repeatedly.

+ * + * @param uri The attribute's Namespace URI, or the empty + * string if none is available. + * @param localName The attribute's local name. + * @return The attribute's index, or -1 if none matches. + * @see org.xml.sax.Attributes#getIndex(java.lang.String,java.lang.String) + */ + @Override + public int getIndex (String uri, String localName) + { + int max = length * 5; + for (int i = 0; i < max; i += 5) { + if (data[i].equals(uri) && data[i+1].equals(localName)) { + return i / 5; + } + } + return -1; + } + + + /** + * Look up an attribute's index by qualified (prefixed) name. + * + * @param qName The qualified name. + * @return The attribute's index, or -1 if none matches. + * @see org.xml.sax.Attributes#getIndex(java.lang.String) + */ + @Override + public int getIndex (String qName) + { + int max = length * 5; + for (int i = 0; i < max; i += 5) { + if (data[i+2].equals(qName)) { + return i / 5; + } + } + return -1; + } + + + /** + * Look up an attribute's type by Namespace-qualified name. + * + * @param uri The Namespace URI, or the empty string for a name + * with no explicit Namespace URI. + * @param localName The local name. + * @return The attribute's type, or null if there is no + * matching attribute. + * @see org.xml.sax.Attributes#getType(java.lang.String,java.lang.String) + */ + @Override + public String getType (String uri, String localName) + { + int max = length * 5; + for (int i = 0; i < max; i += 5) { + if (data[i].equals(uri) && data[i+1].equals(localName)) { + return data[i+3]; + } + } + return null; + } + + + /** + * Look up an attribute's type by qualified (prefixed) name. + * + * @param qName The qualified name. + * @return The attribute's type, or null if there is no + * matching attribute. + * @see org.xml.sax.Attributes#getType(java.lang.String) + */ + @Override + public String getType (String qName) + { + int max = length * 5; + for (int i = 0; i < max; i += 5) { + if (data[i+2].equals(qName)) { + return data[i+3]; + } + } + return null; + } + + + /** + * Look up an attribute's value by Namespace-qualified name. + * + * @param uri The Namespace URI, or the empty string for a name + * with no explicit Namespace URI. + * @param localName The local name. + * @return The attribute's value, or null if there is no + * matching attribute. + * @see org.xml.sax.Attributes#getValue(java.lang.String,java.lang.String) + */ + @Override + public String getValue (String uri, String localName) + { + int max = length * 5; + for (int i = 0; i < max; i += 5) { + if (data[i].equals(uri) && data[i+1].equals(localName)) { + return data[i+4]; + } + } + return null; + } + + + /** + * Look up an attribute's value by qualified (prefixed) name. + * + * @param qName The qualified name. + * @return The attribute's value, or null if there is no + * matching attribute. + * @see org.xml.sax.Attributes#getValue(java.lang.String) + */ + @Override + public String getValue (String qName) + { + int max = length * 5; + for (int i = 0; i < max; i += 5) { + if (data[i+2].equals(qName)) { + return data[i+4]; + } + } + return null; + } + + + + //////////////////////////////////////////////////////////////////// + // Manipulators. + //////////////////////////////////////////////////////////////////// + + + /** + * Clear the attribute list for reuse. + * + *

Note that little memory is freed by this call: + * the current array is kept so it can be + * reused.

+ */ + public void clear () + { + if (data != null) { + for (int i = 0; i < (length * 5); i++) + data [i] = null; + } + length = 0; + } + + + /** + * Copy an entire Attributes object. + * + *

It may be more efficient to reuse an existing object + * rather than constantly allocating new ones.

+ * + * @param atts The attributes to copy. + */ + public void setAttributes (Attributes atts) + { + clear(); + length = atts.getLength(); + if (length > 0) { + data = new String[length*5]; + for (int i = 0; i < length; i++) { + data[i*5] = atts.getURI(i); + data[i*5+1] = atts.getLocalName(i); + data[i*5+2] = atts.getQName(i); + data[i*5+3] = atts.getType(i); + data[i*5+4] = atts.getValue(i); + } + } + } + + + /** + * Add an attribute to the end of the list. + * + *

For the sake of speed, this method does no checking + * to see if the attribute is already in the list: that is + * the responsibility of the application.

+ * + * @param uri The Namespace URI, or the empty string if + * none is available or Namespace processing is not + * being performed. + * @param localName The local name, or the empty string if + * Namespace processing is not being performed. + * @param qName The qualified (prefixed) name, or the empty string + * if qualified names are not available. + * @param type The attribute type as a string. + * @param value The attribute value. + */ + public void addAttribute (String uri, String localName, String qName, + String type, String value) + { + ensureCapacity(length+1); + data[length*5] = uri; + data[length*5+1] = localName; + data[length*5+2] = qName; + data[length*5+3] = type; + data[length*5+4] = value; + length++; + } + + + /** + * Set an attribute in the list. + * + *

For the sake of speed, this method does no checking + * for name conflicts or well-formedness: such checks are the + * responsibility of the application.

+ * + * @param index The index of the attribute (zero-based). + * @param uri The Namespace URI, or the empty string if + * none is available or Namespace processing is not + * being performed. + * @param localName The local name, or the empty string if + * Namespace processing is not being performed. + * @param qName The qualified name, or the empty string + * if qualified names are not available. + * @param type The attribute type as a string. + * @param value The attribute value. + * @exception java.lang.ArrayIndexOutOfBoundsException When the + * supplied index does not point to an attribute + * in the list. + */ + public void setAttribute (int index, String uri, String localName, + String qName, String type, String value) + { + if (index >= 0 && index < length) { + data[index*5] = uri; + data[index*5+1] = localName; + data[index*5+2] = qName; + data[index*5+3] = type; + data[index*5+4] = value; + } else { + badIndex(index); + } + } + + + /** + * Remove an attribute from the list. + * + * @param index The index of the attribute (zero-based). + * @exception java.lang.ArrayIndexOutOfBoundsException When the + * supplied index does not point to an attribute + * in the list. + */ + public void removeAttribute (int index) + { + if (index >= 0 && index < length) { + if (index < length - 1) { + System.arraycopy(data, (index+1)*5, data, index*5, + (length-index-1)*5); + } + index = (length - 1) * 5; + data [index++] = null; + data [index++] = null; + data [index++] = null; + data [index++] = null; + data [index] = null; + length--; + } else { + badIndex(index); + } + } + + + /** + * Set the Namespace URI of a specific attribute. + * + * @param index The index of the attribute (zero-based). + * @param uri The attribute's Namespace URI, or the empty + * string for none. + * @exception java.lang.ArrayIndexOutOfBoundsException When the + * supplied index does not point to an attribute + * in the list. + */ + public void setURI (int index, String uri) + { + if (index >= 0 && index < length) { + data[index*5] = uri; + } else { + badIndex(index); + } + } + + + /** + * Set the local name of a specific attribute. + * + * @param index The index of the attribute (zero-based). + * @param localName The attribute's local name, or the empty + * string for none. + * @exception java.lang.ArrayIndexOutOfBoundsException When the + * supplied index does not point to an attribute + * in the list. + */ + public void setLocalName (int index, String localName) + { + if (index >= 0 && index < length) { + data[index*5+1] = localName; + } else { + badIndex(index); + } + } + + + /** + * Set the qualified name of a specific attribute. + * + * @param index The index of the attribute (zero-based). + * @param qName The attribute's qualified name, or the empty + * string for none. + * @exception java.lang.ArrayIndexOutOfBoundsException When the + * supplied index does not point to an attribute + * in the list. + */ + public void setQName (int index, String qName) + { + if (index >= 0 && index < length) { + data[index*5+2] = qName; + } else { + badIndex(index); + } + } + + + /** + * Set the type of a specific attribute. + * + * @param index The index of the attribute (zero-based). + * @param type The attribute's type. + * @exception java.lang.ArrayIndexOutOfBoundsException When the + * supplied index does not point to an attribute + * in the list. + */ + public void setType (int index, String type) + { + if (index >= 0 && index < length) { + data[index*5+3] = type; + } else { + badIndex(index); + } + } + + + /** + * Set the value of a specific attribute. + * + * @param index The index of the attribute (zero-based). + * @param value The attribute's value. + * @exception java.lang.ArrayIndexOutOfBoundsException When the + * supplied index does not point to an attribute + * in the list. + */ + public void setValue (int index, String value) + { + if (index >= 0 && index < length) { + data[index*5+4] = value; + } else { + badIndex(index); + } + } + + + + //////////////////////////////////////////////////////////////////// + // Internal methods. + //////////////////////////////////////////////////////////////////// + + + /** + * Ensure the internal array's capacity. + * + * @param n The minimum number of attributes that the array must + * be able to hold. + */ + private void ensureCapacity (int n) { + if (n <= 0) { + return; + } + int max; + if (data == null || data.length == 0) { + max = 25; + } + else if (data.length >= n * 5) { + return; + } + else { + max = data.length; + } + while (max < n * 5) { + max *= 2; + } + + String newData[] = new String[max]; + if (length > 0) { + System.arraycopy(data, 0, newData, 0, length*5); + } + data = newData; + } + + + /** + * Report a bad array index in a manipulator. + * + * @param index The index to report. + * @exception java.lang.ArrayIndexOutOfBoundsException Always. + */ + private void badIndex (int index) + throws ArrayIndexOutOfBoundsException + { + String msg = + "Attempt to modify attribute at illegal index: " + index; + throw new ArrayIndexOutOfBoundsException(msg); + } + + + + //////////////////////////////////////////////////////////////////// + // Internal state. + //////////////////////////////////////////////////////////////////// + + int length; + String data []; + +} + +// end of AttributesImpl.java + diff --git a/src/org/xml/sax/helpers/DefaultHandler.java b/src/org/xml/sax/helpers/DefaultHandler.java new file mode 100644 index 0000000..83bde62 --- /dev/null +++ b/src/org/xml/sax/helpers/DefaultHandler.java @@ -0,0 +1,484 @@ +// DefaultHandler.java - default implementation of the core handlers. +// http://www.saxproject.org +// Written by David Megginson +// NO WARRANTY! This class is in the public domain. +// $Id: DefaultHandler.java,v 1.9 2004/04/26 17:34:35 dmegginson Exp $ + +package org.xml.sax.helpers; + +import java.io.IOException; + +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.Attributes; +import org.xml.sax.EntityResolver; +import org.xml.sax.DTDHandler; +import org.xml.sax.ContentHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + + +/** + * Default base class for SAX2 event handlers. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This class is available as a convenience base class for SAX2 + * applications: it provides default implementations for all of the + * callbacks in the four core SAX2 handler classes:

+ * + *
    + *
  • {@link org.xml.sax.EntityResolver EntityResolver}
  • + *
  • {@link org.xml.sax.DTDHandler DTDHandler}
  • + *
  • {@link org.xml.sax.ContentHandler ContentHandler}
  • + *
  • {@link org.xml.sax.ErrorHandler ErrorHandler}
  • + *
+ * + *

Application writers can extend this class when they need to + * implement only part of an interface; parser writers can + * instantiate this class to provide default handlers when the + * application has not supplied its own.

+ * + *

This class replaces the deprecated SAX1 + * {@link org.xml.sax.HandlerBase HandlerBase} class.

+ * + * @since SAX 2.0 + * @author David Megginson, + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.EntityResolver + * @see org.xml.sax.DTDHandler + * @see org.xml.sax.ContentHandler + * @see org.xml.sax.ErrorHandler + */ +public class DefaultHandler + implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler +{ + + + //////////////////////////////////////////////////////////////////// + // Default implementation of the EntityResolver interface. + //////////////////////////////////////////////////////////////////// + + /** + * Resolve an external entity. + * + *

Always return null, so that the parser will use the system + * identifier provided in the XML document. This method implements + * the SAX default behaviour: application writers can override it + * in a subclass to do special translations such as catalog lookups + * or URI redirection.

+ * + * @param publicId The public identifer, or null if none is + * available. + * @param systemId The system identifier provided in the XML + * document. + * @return The new input source, or null to require the + * default behaviour. + * @exception java.io.IOException If there is an error setting + * up the new input source. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.EntityResolver#resolveEntity + */ + @Override + public InputSource resolveEntity (String publicId, String systemId) + throws IOException, SAXException + { + return null; + } + + + + //////////////////////////////////////////////////////////////////// + // Default implementation of DTDHandler interface. + //////////////////////////////////////////////////////////////////// + + + /** + * Receive notification of a notation declaration. + * + *

By default, do nothing. Application writers may override this + * method in a subclass if they wish to keep track of the notations + * declared in a document.

+ * + * @param name The notation name. + * @param publicId The notation public identifier, or null if not + * available. + * @param systemId The notation system identifier. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.DTDHandler#notationDecl + */ + @Override + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + // no op + } + + + /** + * Receive notification of an unparsed entity declaration. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to keep track of the unparsed entities + * declared in a document.

+ * + * @param name The entity name. + * @param publicId The entity public identifier, or null if not + * available. + * @param systemId The entity system identifier. + * @param notationName The name of the associated notation. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.DTDHandler#unparsedEntityDecl + */ + @Override + public void unparsedEntityDecl (String name, String publicId, + String systemId, String notationName) + throws SAXException + { + // no op + } + + + + //////////////////////////////////////////////////////////////////// + // Default implementation of ContentHandler interface. + //////////////////////////////////////////////////////////////////// + + + /** + * Receive a Locator object for document events. + * + *

By default, do nothing. Application writers may override this + * method in a subclass if they wish to store the locator for use + * with other document events.

+ * + * @param locator A locator for all SAX document events. + * @see org.xml.sax.ContentHandler#setDocumentLocator + * @see org.xml.sax.Locator + */ + @Override + public void setDocumentLocator (Locator locator) + { + // no op + } + + + /** + * Receive notification of the beginning of the document. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions at the beginning + * of a document (such as allocating the root node of a tree or + * creating an output file).

+ * + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ContentHandler#startDocument + */ + @Override + public void startDocument () + throws SAXException + { + // no op + } + + + /** + * Receive notification of the end of the document. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions at the end + * of a document (such as finalising a tree or closing an output + * file).

+ * + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ContentHandler#endDocument + */ + @Override + public void endDocument () + throws SAXException + { + // no op + } + + + /** + * Receive notification of the start of a Namespace mapping. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions at the start of + * each Namespace prefix scope (such as storing the prefix mapping).

+ * + * @param prefix The Namespace prefix being declared. + * @param uri The Namespace URI mapped to the prefix. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ContentHandler#startPrefixMapping + */ + @Override + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + // no op + } + + + /** + * Receive notification of the end of a Namespace mapping. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions at the end of + * each prefix mapping.

+ * + * @param prefix The Namespace prefix being declared. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ContentHandler#endPrefixMapping + */ + @Override + public void endPrefixMapping (String prefix) + throws SAXException + { + // no op + } + + + /** + * Receive notification of the start of an element. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions at the start of + * each element (such as allocating a new tree node or writing + * output to a file).

+ * + * @param uri The Namespace URI, or the empty string if the + * element has no Namespace URI or if Namespace + * processing is not being performed. + * @param localName The local name (without prefix), or the + * empty string if Namespace processing is not being + * performed. + * @param qName The qualified name (with prefix), or the + * empty string if qualified names are not available. + * @param attributes The attributes attached to the element. If + * there are no attributes, it shall be an empty + * Attributes object. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ContentHandler#startElement + */ + @Override + public void startElement (String uri, String localName, + String qName, Attributes attributes) + throws SAXException + { + // no op + } + + + /** + * Receive notification of the end of an element. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions at the end of + * each element (such as finalising a tree node or writing + * output to a file).

+ * + * @param uri The Namespace URI, or the empty string if the + * element has no Namespace URI or if Namespace + * processing is not being performed. + * @param localName The local name (without prefix), or the + * empty string if Namespace processing is not being + * performed. + * @param qName The qualified name (with prefix), or the + * empty string if qualified names are not available. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ContentHandler#endElement + */ + @Override + public void endElement (String uri, String localName, String qName) + throws SAXException + { + // no op + } + + + /** + * Receive notification of character data inside an element. + * + *

By default, do nothing. Application writers may override this + * method to take specific actions for each chunk of character data + * (such as adding the data to a node or buffer, or printing it to + * a file).

+ * + * @param ch The characters. + * @param start The start position in the character array. + * @param length The number of characters to use from the + * character array. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ContentHandler#characters + */ + @Override + public void characters (char ch[], int start, int length) + throws SAXException + { + // no op + } + + + /** + * Receive notification of ignorable whitespace in element content. + * + *

By default, do nothing. Application writers may override this + * method to take specific actions for each chunk of ignorable + * whitespace (such as adding data to a node or buffer, or printing + * it to a file).

+ * + * @param ch The whitespace characters. + * @param start The start position in the character array. + * @param length The number of characters to use from the + * character array. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ContentHandler#ignorableWhitespace + */ + @Override + public void ignorableWhitespace (char ch[], int start, int length) + throws SAXException + { + // no op + } + + + /** + * Receive notification of a processing instruction. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions for each + * processing instruction, such as setting status variables or + * invoking other methods.

+ * + * @param target The processing instruction target. + * @param data The processing instruction data, or null if + * none is supplied. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ContentHandler#processingInstruction + */ + @Override + public void processingInstruction (String target, String data) + throws SAXException + { + // no op + } + + + /** + * Receive notification of a skipped entity. + * + *

By default, do nothing. Application writers may override this + * method in a subclass to take specific actions for each + * processing instruction, such as setting status variables or + * invoking other methods.

+ * + * @param name The name of the skipped entity. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ContentHandler#processingInstruction + */ + @Override + public void skippedEntity (String name) + throws SAXException + { + // no op + } + + + + //////////////////////////////////////////////////////////////////// + // Default implementation of the ErrorHandler interface. + //////////////////////////////////////////////////////////////////// + + + /** + * Receive notification of a parser warning. + * + *

The default implementation does nothing. Application writers + * may override this method in a subclass to take specific actions + * for each warning, such as inserting the message in a log file or + * printing it to the console.

+ * + * @param e The warning information encoded as an exception. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ErrorHandler#warning + * @see org.xml.sax.SAXParseException + */ + @Override + public void warning (SAXParseException e) + throws SAXException + { + // no op + } + + + /** + * Receive notification of a recoverable parser error. + * + *

The default implementation does nothing. Application writers + * may override this method in a subclass to take specific actions + * for each error, such as inserting the message in a log file or + * printing it to the console.

+ * + * @param e The warning information encoded as an exception. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ErrorHandler#warning + * @see org.xml.sax.SAXParseException + */ + @Override + public void error (SAXParseException e) + throws SAXException + { + // no op + } + + + /** + * Report a fatal XML parsing error. + * + *

The default implementation throws a SAXParseException. + * Application writers may override this method in a subclass if + * they need to take specific actions for each fatal error (such as + * collecting all of the errors into a single report): in any case, + * the application must stop all regular processing when this + * method is invoked, since the document is no longer reliable, and + * the parser may no longer report parsing events.

+ * + * @param e The error information encoded as an exception. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @see org.xml.sax.ErrorHandler#fatalError + * @see org.xml.sax.SAXParseException + */ + @Override + public void fatalError (SAXParseException e) + throws SAXException + { + throw e; + } + +} + +// end of DefaultHandler.java diff --git a/src/org/xml/sax/helpers/LocatorImpl.java b/src/org/xml/sax/helpers/LocatorImpl.java new file mode 100644 index 0000000..90eab7e --- /dev/null +++ b/src/org/xml/sax/helpers/LocatorImpl.java @@ -0,0 +1,218 @@ +// SAX default implementation for Locator. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: LocatorImpl.java,v 1.6 2002/01/30 20:52:27 dbrownell Exp $ + +package org.xml.sax.helpers; + +import org.xml.sax.Locator; + + +/** + * Provide an optional convenience implementation of Locator. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This class is available mainly for application writers, who + * can use it to make a persistent snapshot of a locator at any + * point during a document parse:

+ * + *
+ * Locator locator;
+ * Locator startloc;
+ *
+ * public void setLocator (Locator locator)
+ * {
+ *         // note the locator
+ *   this.locator = locator;
+ * }
+ *
+ * public void startDocument ()
+ * {
+ *         // save the location of the start of the document
+ *         // for future use.
+ *   Locator startloc = new LocatorImpl(locator);
+ * }
+ *
+ * + *

Normally, parser writers will not use this class, since it + * is more efficient to provide location information only when + * requested, rather than constantly updating a Locator object.

+ * + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.Locator Locator + */ +public class LocatorImpl implements Locator +{ + + + /** + * Zero-argument constructor. + * + *

This will not normally be useful, since the main purpose + * of this class is to make a snapshot of an existing Locator.

+ */ + public LocatorImpl () + { + } + + + /** + * Copy constructor. + * + *

Create a persistent copy of the current state of a locator. + * When the original locator changes, this copy will still keep + * the original values (and it can be used outside the scope of + * DocumentHandler methods).

+ * + * @param locator The locator to copy. + */ + public LocatorImpl (Locator locator) + { + setPublicId(locator.getPublicId()); + setSystemId(locator.getSystemId()); + setLineNumber(locator.getLineNumber()); + setColumnNumber(locator.getColumnNumber()); + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.Locator + //////////////////////////////////////////////////////////////////// + + + /** + * Return the saved public identifier. + * + * @return The public identifier as a string, or null if none + * is available. + * @see org.xml.sax.Locator#getPublicId + * @see #setPublicId + */ + @Override + public String getPublicId () + { + return publicId; + } + + + /** + * Return the saved system identifier. + * + * @return The system identifier as a string, or null if none + * is available. + * @see org.xml.sax.Locator#getSystemId + * @see #setSystemId + */ + @Override + public String getSystemId () + { + return systemId; + } + + + /** + * Return the saved line number (1-based). + * + * @return The line number as an integer, or -1 if none is available. + * @see org.xml.sax.Locator#getLineNumber + * @see #setLineNumber + */ + @Override + public int getLineNumber () + { + return lineNumber; + } + + + /** + * Return the saved column number (1-based). + * + * @return The column number as an integer, or -1 if none is available. + * @see org.xml.sax.Locator#getColumnNumber + * @see #setColumnNumber + */ + @Override + public int getColumnNumber () + { + return columnNumber; + } + + + + //////////////////////////////////////////////////////////////////// + // Setters for the properties (not in org.xml.sax.Locator) + //////////////////////////////////////////////////////////////////// + + + /** + * Set the public identifier for this locator. + * + * @param publicId The new public identifier, or null + * if none is available. + * @see #getPublicId + */ + public void setPublicId (String publicId) + { + this.publicId = publicId; + } + + + /** + * Set the system identifier for this locator. + * + * @param systemId The new system identifier, or null + * if none is available. + * @see #getSystemId + */ + public void setSystemId (String systemId) + { + this.systemId = systemId; + } + + + /** + * Set the line number for this locator (1-based). + * + * @param lineNumber The line number, or -1 if none is available. + * @see #getLineNumber + */ + public void setLineNumber (int lineNumber) + { + this.lineNumber = lineNumber; + } + + + /** + * Set the column number for this locator (1-based). + * + * @param columnNumber The column number, or -1 if none is available. + * @see #getColumnNumber + */ + public void setColumnNumber (int columnNumber) + { + this.columnNumber = columnNumber; + } + + + + //////////////////////////////////////////////////////////////////// + // Internal state. + //////////////////////////////////////////////////////////////////// + + private String publicId; + private String systemId; + private int lineNumber; + private int columnNumber; + +} + +// end of LocatorImpl.java diff --git a/src/org/xml/sax/helpers/NamespaceSupport.java b/src/org/xml/sax/helpers/NamespaceSupport.java new file mode 100644 index 0000000..3c15f5e --- /dev/null +++ b/src/org/xml/sax/helpers/NamespaceSupport.java @@ -0,0 +1,835 @@ +// NamespaceSupport.java - generic Namespace support for SAX. +// http://www.saxproject.org +// Written by David Megginson +// This class is in the Public Domain. NO WARRANTY! +// $Id: NamespaceSupport.java,v 1.15 2004/04/26 17:34:35 dmegginson Exp $ + +package org.xml.sax.helpers; + +import java.util.EmptyStackException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + + +/** + * Encapsulate Namespace logic for use by applications using SAX, + * or internally by SAX drivers. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This class encapsulates the logic of Namespace processing: it + * tracks the declarations currently in force for each context and + * automatically processes qualified XML names into their Namespace + * parts; it can also be used in reverse for generating XML qnames + * from Namespaces.

+ * + *

Namespace support objects are reusable, but the reset method + * must be invoked between each session.

+ * + *

Here is a simple session:

+ * + *
+ * String parts[] = new String[3];
+ * NamespaceSupport support = new NamespaceSupport();
+ *
+ * support.pushContext();
+ * support.declarePrefix("", "http://www.w3.org/1999/xhtml");
+ * support.declarePrefix("dc", "http://www.purl.org/dc#");
+ *
+ * parts = support.processName("p", parts, false);
+ * System.out.println("Namespace URI: " + parts[0]);
+ * System.out.println("Local name: " + parts[1]);
+ * System.out.println("Raw name: " + parts[2]);
+ *
+ * parts = support.processName("dc:title", parts, false);
+ * System.out.println("Namespace URI: " + parts[0]);
+ * System.out.println("Local name: " + parts[1]);
+ * System.out.println("Raw name: " + parts[2]);
+ *
+ * support.popContext();
+ * 
+ * + *

Note that this class is optimized for the use case where most + * elements do not contain Namespace declarations: if the same + * prefix/URI mapping is repeated for each context (for example), this + * class will be somewhat less efficient.

+ * + *

Although SAX drivers (parsers) may choose to use this class to + * implement namespace handling, they are not required to do so. + * Applications must track namespace information themselves if they + * want to use namespace information. + * + * @since SAX 2.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + */ +public class NamespaceSupport +{ + + + //////////////////////////////////////////////////////////////////// + // Constants. + //////////////////////////////////////////////////////////////////// + + + /** + * The XML Namespace URI as a constant. + * The value is http://www.w3.org/XML/1998/namespace + * as defined in the "Namespaces in XML" * recommendation. + * + *

This is the Namespace URI that is automatically mapped + * to the "xml" prefix.

+ */ + public final static String XMLNS = + "http://www.w3.org/XML/1998/namespace"; + + + /** + * The namespace declaration URI as a constant. + * The value is http://www.w3.org/xmlns/2000/, as defined + * in a backwards-incompatible erratum to the "Namespaces in XML" + * recommendation. Because that erratum postdated SAX2, SAX2 defaults + * to the original recommendation, and does not normally use this URI. + * + * + *

This is the Namespace URI that is optionally applied to + * xmlns and xmlns:* attributes, which are used to + * declare namespaces.

+ * + * @since SAX 2.1alpha + * @see #setNamespaceDeclUris + * @see #isNamespaceDeclUris + */ + public final static String NSDECL = + "http://www.w3.org/xmlns/2000/"; + + + /** + * An empty enumeration. + */ + private final static Enumeration EMPTY_ENUMERATION = + new Vector().elements(); + + + //////////////////////////////////////////////////////////////////// + // Constructor. + //////////////////////////////////////////////////////////////////// + + + /** + * Create a new Namespace support object. + */ + public NamespaceSupport () + { + reset(); + } + + + + //////////////////////////////////////////////////////////////////// + // Context management. + //////////////////////////////////////////////////////////////////// + + + /** + * Reset this Namespace support object for reuse. + * + *

It is necessary to invoke this method before reusing the + * Namespace support object for a new session. If namespace + * declaration URIs are to be supported, that flag must also + * be set to a non-default value. + *

+ * + * @see #setNamespaceDeclUris + */ + public void reset () + { + contexts = new Context[32]; + namespaceDeclUris = false; + contextPos = 0; + contexts[contextPos] = currentContext = new Context(); + currentContext.declarePrefix("xml", XMLNS); + } + + + /** + * Start a new Namespace context. + * The new context will automatically inherit + * the declarations of its parent context, but it will also keep + * track of which declarations were made within this context. + * + *

Event callback code should start a new context once per element. + * This means being ready to call this in either of two places. + * For elements that don't include namespace declarations, the + * ContentHandler.startElement() callback is the right place. + * For elements with such a declaration, it'd done in the first + * ContentHandler.startPrefixMapping() callback. + * A boolean flag can be used to + * track whether a context has been started yet. When either of + * those methods is called, it checks the flag to see if a new context + * needs to be started. If so, it starts the context and sets the + * flag. After ContentHandler.startElement() + * does that, it always clears the flag. + * + *

Normally, SAX drivers would push a new context at the beginning + * of each XML element. Then they perform a first pass over the + * attributes to process all namespace declarations, making + * ContentHandler.startPrefixMapping() callbacks. + * Then a second pass is made, to determine the namespace-qualified + * names for all attributes and for the element name. + * Finally all the information for the + * ContentHandler.startElement() callback is available, + * so it can then be made. + * + *

The Namespace support object always starts with a base context + * already in force: in this context, only the "xml" prefix is + * declared.

+ * + * @see org.xml.sax.ContentHandler + * @see #popContext + */ + public void pushContext () + { + int max = contexts.length; + + contexts [contextPos].declsOK = false; + contextPos++; + + // Extend the array if necessary + if (contextPos >= max) { + Context newContexts[] = new Context[max*2]; + System.arraycopy(contexts, 0, newContexts, 0, max); + max *= 2; + contexts = newContexts; + } + + // Allocate the context if necessary. + currentContext = contexts[contextPos]; + if (currentContext == null) { + contexts[contextPos] = currentContext = new Context(); + } + + // Set the parent, if any. + if (contextPos > 0) { + currentContext.setParent(contexts[contextPos - 1]); + } + } + + + /** + * Revert to the previous Namespace context. + * + *

Normally, you should pop the context at the end of each + * XML element. After popping the context, all Namespace prefix + * mappings that were previously in force are restored.

+ * + *

You must not attempt to declare additional Namespace + * prefixes after popping a context, unless you push another + * context first.

+ * + * @see #pushContext + */ + public void popContext () + { + contexts[contextPos].clear(); + contextPos--; + if (contextPos < 0) { + throw new EmptyStackException(); + } + currentContext = contexts[contextPos]; + } + + + + //////////////////////////////////////////////////////////////////// + // Operations within a context. + //////////////////////////////////////////////////////////////////// + + + /** + * Declare a Namespace prefix. All prefixes must be declared + * before they are referenced. For example, a SAX driver (parser) + * would scan an element's attributes + * in two passes: first for namespace declarations, + * then a second pass using {@link #processName processName()} to + * interpret prefixes against (potentially redefined) prefixes. + * + *

This method declares a prefix in the current Namespace + * context; the prefix will remain in force until this context + * is popped, unless it is shadowed in a descendant context.

+ * + *

To declare the default element Namespace, use the empty string as + * the prefix.

+ * + *

Note that you must not declare a prefix after + * you've pushed and popped another Namespace context, or + * treated the declarations phase as complete by processing + * a prefixed name.

+ * + *

Note that there is an asymmetry in this library: {@link + * #getPrefix getPrefix} will not return the "" prefix, + * even if you have declared a default element namespace. + * To check for a default namespace, + * you have to look it up explicitly using {@link #getURI getURI}. + * This asymmetry exists to make it easier to look up prefixes + * for attribute names, where the default prefix is not allowed.

+ * + * @param prefix The prefix to declare, or the empty string to + * indicate the default element namespace. This may never have + * the value "xml" or "xmlns". + * @param uri The Namespace URI to associate with the prefix. + * @return true if the prefix was legal, false otherwise + * + * @see #processName + * @see #getURI + * @see #getPrefix + */ + public boolean declarePrefix (String prefix, String uri) + { + if (prefix.equals("xml") || prefix.equals("xmlns")) { + return false; + } else { + currentContext.declarePrefix(prefix, uri); + return true; + } + } + + + /** + * Process a raw XML qualified name, after all declarations in the + * current context have been handled by {@link #declarePrefix + * declarePrefix()}. + * + *

This method processes a raw XML qualified name in the + * current context by removing the prefix and looking it up among + * the prefixes currently declared. The return value will be the + * array supplied by the caller, filled in as follows:

+ * + *
+ *
parts[0]
+ *
The Namespace URI, or an empty string if none is + * in use.
+ *
parts[1]
+ *
The local name (without prefix).
+ *
parts[2]
+ *
The original raw name.
+ *
+ * + *

All of the strings in the array will be internalized. If + * the raw name has a prefix that has not been declared, then + * the return value will be null.

+ * + *

Note that attribute names are processed differently than + * element names: an unprefixed element name will receive the + * default Namespace (if any), while an unprefixed attribute name + * will not.

+ * + * @param qName The XML qualified name to be processed. + * @param parts An array supplied by the caller, capable of + * holding at least three members. + * @param isAttribute A flag indicating whether this is an + * attribute name (true) or an element name (false). + * @return The supplied array holding three internalized strings + * representing the Namespace URI (or empty string), the + * local name, and the XML qualified name; or null if there + * is an undeclared prefix. + * @see #declarePrefix + * @see java.lang.String#intern */ + public String [] processName (String qName, String parts[], + boolean isAttribute) + { + String myParts[] = currentContext.processName(qName, isAttribute); + if (myParts == null) { + return null; + } else { + parts[0] = myParts[0]; + parts[1] = myParts[1]; + parts[2] = myParts[2]; + return parts; + } + } + + + /** + * Look up a prefix and get the currently-mapped Namespace URI. + * + *

This method looks up the prefix in the current context. + * Use the empty string ("") for the default Namespace.

+ * + * @param prefix The prefix to look up. + * @return The associated Namespace URI, or null if the prefix + * is undeclared in this context. + * @see #getPrefix + * @see #getPrefixes + */ + public String getURI (String prefix) + { + return currentContext.getURI(prefix); + } + + + /** + * Return an enumeration of all prefixes whose declarations are + * active in the current context. + * This includes declarations from parent contexts that have + * not been overridden. + * + *

Note: if there is a default prefix, it will not be + * returned in this enumeration; check for the default prefix + * using the {@link #getURI getURI} with an argument of "".

+ * + * @return An enumeration of prefixes (never empty). + * @see #getDeclaredPrefixes + * @see #getURI + */ + public Enumeration getPrefixes () + { + return currentContext.getPrefixes(); + } + + + /** + * Return one of the prefixes mapped to a Namespace URI. + * + *

If more than one prefix is currently mapped to the same + * URI, this method will make an arbitrary selection; if you + * want all of the prefixes, use the {@link #getPrefixes} + * method instead.

+ * + *

Note: this will never return the empty (default) prefix; + * to check for a default prefix, use the {@link #getURI getURI} + * method with an argument of "".

+ * + * @param uri the namespace URI + * @return one of the prefixes currently mapped to the URI supplied, + * or null if none is mapped or if the URI is assigned to + * the default namespace + * @see #getPrefixes(java.lang.String) + * @see #getURI + */ + public String getPrefix (String uri) + { + return currentContext.getPrefix(uri); + } + + + /** + * Return an enumeration of all prefixes for a given URI whose + * declarations are active in the current context. + * This includes declarations from parent contexts that have + * not been overridden. + * + *

This method returns prefixes mapped to a specific Namespace + * URI. The xml: prefix will be included. If you want only one + * prefix that's mapped to the Namespace URI, and you don't care + * which one you get, use the {@link #getPrefix getPrefix} + * method instead.

+ * + *

Note: the empty (default) prefix is never included + * in this enumeration; to check for the presence of a default + * Namespace, use the {@link #getURI getURI} method with an + * argument of "".

+ * + * @param uri The Namespace URI. + * @return An enumeration of prefixes (never empty). + * @see #getPrefix + * @see #getDeclaredPrefixes + * @see #getURI + */ + public Enumeration getPrefixes (String uri) + { + Vector prefixes = new Vector(); + Enumeration allPrefixes = getPrefixes(); + while (allPrefixes.hasMoreElements()) { + String prefix = (String)allPrefixes.nextElement(); + if (uri.equals(getURI(prefix))) { + prefixes.addElement(prefix); + } + } + return prefixes.elements(); + } + + + /** + * Return an enumeration of all prefixes declared in this context. + * + *

The empty (default) prefix will be included in this + * enumeration; note that this behaviour differs from that of + * {@link #getPrefix} and {@link #getPrefixes}.

+ * + * @return An enumeration of all prefixes declared in this + * context. + * @see #getPrefixes + * @see #getURI + */ + public Enumeration getDeclaredPrefixes () + { + return currentContext.getDeclaredPrefixes(); + } + + /** + * Controls whether namespace declaration attributes are placed + * into the {@link #NSDECL NSDECL} namespace + * by {@link #processName processName()}. This may only be + * changed before any contexts have been pushed. + * + * @since SAX 2.1alpha + * + * @exception IllegalStateException when attempting to set this + * after any context has been pushed. + */ + public void setNamespaceDeclUris (boolean value) + { + if (contextPos != 0) + throw new IllegalStateException (); + if (value == namespaceDeclUris) + return; + namespaceDeclUris = value; + if (value) + currentContext.declarePrefix ("xmlns", NSDECL); + else { + contexts[contextPos] = currentContext = new Context(); + currentContext.declarePrefix("xml", XMLNS); + } + } + + /** + * Returns true if namespace declaration attributes are placed into + * a namespace. This behavior is not the default. + * + * @since SAX 2.1alpha + */ + public boolean isNamespaceDeclUris () + { return namespaceDeclUris; } + + + + //////////////////////////////////////////////////////////////////// + // Internal state. + //////////////////////////////////////////////////////////////////// + + private Context contexts[]; + private Context currentContext; + private int contextPos; + private boolean namespaceDeclUris; + + + //////////////////////////////////////////////////////////////////// + // Internal classes. + //////////////////////////////////////////////////////////////////// + + /** + * Internal class for a single Namespace context. + * + *

This module caches and reuses Namespace contexts, + * so the number allocated + * will be equal to the element depth of the document, not to the total + * number of elements (i.e. 5-10 rather than tens of thousands). + * Also, data structures used to represent contexts are shared when + * possible (child contexts without declarations) to further reduce + * the amount of memory that's consumed. + *

+ */ + final class Context { + + /** + * Create the root-level Namespace context. + */ + Context () + { + copyTables(); + } + + + /** + * (Re)set the parent of this Namespace context. + * The context must either have been freshly constructed, + * or must have been cleared. + * + * @param context The parent Namespace context object. + */ + void setParent (Context parent) + { + this.parent = parent; + declarations = null; + prefixTable = parent.prefixTable; + uriTable = parent.uriTable; + elementNameTable = parent.elementNameTable; + attributeNameTable = parent.attributeNameTable; + defaultNS = parent.defaultNS; + declSeen = false; + declsOK = true; + } + + /** + * Makes associated state become collectible, + * invalidating this context. + * {@link #setParent} must be called before + * this context may be used again. + */ + void clear () + { + parent = null; + prefixTable = null; + uriTable = null; + elementNameTable = null; + attributeNameTable = null; + defaultNS = null; + } + + + /** + * Declare a Namespace prefix for this context. + * + * @param prefix The prefix to declare. + * @param uri The associated Namespace URI. + * @see org.xml.sax.helpers.NamespaceSupport#declarePrefix + */ + void declarePrefix (String prefix, String uri) + { + // Lazy processing... + if (!declsOK) + throw new IllegalStateException ( + "can't declare any more prefixes in this context"); + if (!declSeen) { + copyTables(); + } + if (declarations == null) { + declarations = new Vector(); + } + + prefix = prefix.intern(); + uri = uri.intern(); + if ("".equals(prefix)) { + if ("".equals(uri)) { + defaultNS = null; + } else { + defaultNS = uri; + } + } else { + prefixTable.put(prefix, uri); + uriTable.put(uri, prefix); // may wipe out another prefix + } + declarations.addElement(prefix); + } + + + /** + * Process an XML qualified name in this context. + * + * @param qName The XML qualified name. + * @param isAttribute true if this is an attribute name. + * @return An array of three strings containing the + * URI part (or empty string), the local part, + * and the raw name, all internalized, or null + * if there is an undeclared prefix. + * @see org.xml.sax.helpers.NamespaceSupport#processName + */ + String [] processName (String qName, boolean isAttribute) + { + String name[]; + Hashtable table; + + // detect errors in call sequence + declsOK = false; + + // Select the appropriate table. + if (isAttribute) { + table = attributeNameTable; + } else { + table = elementNameTable; + } + + // Start by looking in the cache, and + // return immediately if the name + // is already known in this content + name = (String[])table.get(qName); + if (name != null) { + return name; + } + + // We haven't seen this name in this + // context before. Maybe in the parent + // context, but we can't assume prefix + // bindings are the same. + name = new String[3]; + name[2] = qName.intern(); + int index = qName.indexOf(':'); + + + // No prefix. + if (index == -1) { + if (isAttribute) { + if (qName == "xmlns" && namespaceDeclUris) + name[0] = NSDECL; + else + name[0] = ""; + } else if (defaultNS == null) { + name[0] = ""; + } else { + name[0] = defaultNS; + } + name[1] = name[2]; + } + + // Prefix + else { + String prefix = qName.substring(0, index); + String local = qName.substring(index+1); + String uri; + if ("".equals(prefix)) { + uri = defaultNS; + } else { + uri = (String)prefixTable.get(prefix); + } + if (uri == null + || (!isAttribute && "xmlns".equals (prefix))) { + return null; + } + name[0] = uri; + name[1] = local.intern(); + } + + // Save in the cache for future use. + // (Could be shared with parent context...) + table.put(name[2], name); + return name; + } + + + /** + * Look up the URI associated with a prefix in this context. + * + * @param prefix The prefix to look up. + * @return The associated Namespace URI, or null if none is + * declared. + * @see org.xml.sax.helpers.NamespaceSupport#getURI + */ + String getURI (String prefix) + { + if ("".equals(prefix)) { + return defaultNS; + } else if (prefixTable == null) { + return null; + } else { + return (String)prefixTable.get(prefix); + } + } + + + /** + * Look up one of the prefixes associated with a URI in this context. + * + *

Since many prefixes may be mapped to the same URI, + * the return value may be unreliable.

+ * + * @param uri The URI to look up. + * @return The associated prefix, or null if none is declared. + * @see org.xml.sax.helpers.NamespaceSupport#getPrefix + */ + String getPrefix (String uri) + { + if (uriTable == null) { + return null; + } else { + return (String)uriTable.get(uri); + } + } + + + /** + * Return an enumeration of prefixes declared in this context. + * + * @return An enumeration of prefixes (possibly empty). + * @see org.xml.sax.helpers.NamespaceSupport#getDeclaredPrefixes + */ + Enumeration getDeclaredPrefixes () + { + if (declarations == null) { + return EMPTY_ENUMERATION; + } else { + return declarations.elements(); + } + } + + + /** + * Return an enumeration of all prefixes currently in force. + * + *

The default prefix, if in force, is not + * returned, and will have to be checked for separately.

+ * + * @return An enumeration of prefixes (never empty). + * @see org.xml.sax.helpers.NamespaceSupport#getPrefixes + */ + Enumeration getPrefixes () + { + if (prefixTable == null) { + return EMPTY_ENUMERATION; + } else { + return prefixTable.keys(); + } + } + + + + //////////////////////////////////////////////////////////////// + // Internal methods. + //////////////////////////////////////////////////////////////// + + + /** + * Copy on write for the internal tables in this context. + * + *

This class is optimized for the normal case where most + * elements do not contain Namespace declarations.

+ */ + private void copyTables () + { + if (prefixTable != null) { + prefixTable = (Hashtable)prefixTable.clone(); + } else { + prefixTable = new Hashtable(); + } + if (uriTable != null) { + uriTable = (Hashtable)uriTable.clone(); + } else { + uriTable = new Hashtable(); + } + elementNameTable = new Hashtable(); + attributeNameTable = new Hashtable(); + declSeen = true; + } + + + + //////////////////////////////////////////////////////////////// + // Protected state. + //////////////////////////////////////////////////////////////// + + Hashtable prefixTable; + Hashtable uriTable; + Hashtable elementNameTable; + Hashtable attributeNameTable; + String defaultNS = null; + boolean declsOK = true; + + + + //////////////////////////////////////////////////////////////// + // Internal state. + //////////////////////////////////////////////////////////////// + + private Vector declarations = null; + private boolean declSeen = false; + private Context parent = null; + } +} + +// end of NamespaceSupport.java diff --git a/src/org/xml/sax/helpers/NewInstance.java b/src/org/xml/sax/helpers/NewInstance.java new file mode 100644 index 0000000..6fc34d6 --- /dev/null +++ b/src/org/xml/sax/helpers/NewInstance.java @@ -0,0 +1,79 @@ +// NewInstance.java - create a new instance of a class by name. +// http://www.saxproject.org +// Written by Edwin Goei, edwingo@apache.org +// and by David Brownell, dbrownell@users.sourceforge.net +// NO WARRANTY! This class is in the Public Domain. +// $Id: NewInstance.java,v 1.4 2002/01/30 20:52:27 dbrownell Exp $ + +package org.xml.sax.helpers; + +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; + +/** + * Create a new instance of a class by name. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This class contains a static method for creating an instance of a + * class from an explicit class name. It tries to use the thread's context + * ClassLoader if possible and falls back to using + * Class.forName(String).

+ * + *

This code is designed to compile and run on JDK version 1.1 and later + * including versions of Java 2.

+ * + * @author Edwin Goei, David Brownell + * @version 2.0.1 (sax2r2) + */ +class NewInstance { + + /** + * Creates a new instance of the specified class name + * + * Package private so this code is not exposed at the API level. + */ + static Object newInstance (ClassLoader classLoader, String className) + throws ClassNotFoundException, IllegalAccessException, + InstantiationException + { + Class driverClass; + if (classLoader == null) { + driverClass = Class.forName(className); + } else { + driverClass = classLoader.loadClass(className); + } + return driverClass.newInstance(); + } + + /** + * Figure out which ClassLoader to use. For JDK 1.2 and later use + * the context ClassLoader. + */ + static ClassLoader getClassLoader () + { + Method m = null; + + try { + m = Thread.class.getMethod("getContextClassLoader", null); + } catch (NoSuchMethodException e) { + // Assume that we are running JDK 1.1, use the current ClassLoader + return NewInstance.class.getClassLoader(); + } + + try { + return (ClassLoader) m.invoke(Thread.currentThread(), null); + } catch (IllegalAccessException e) { + // assert(false) + throw new UnknownError(e.getMessage()); + } catch (InvocationTargetException e) { + // assert(e.getTargetException() instanceof SecurityException) + throw new UnknownError(e.getMessage()); + } + } +} diff --git a/src/org/xml/sax/helpers/ParserAdapter.java b/src/org/xml/sax/helpers/ParserAdapter.java new file mode 100644 index 0000000..b723219 --- /dev/null +++ b/src/org/xml/sax/helpers/ParserAdapter.java @@ -0,0 +1,1080 @@ +// ParserAdapter.java - adapt a SAX1 Parser to a SAX2 XMLReader. +// http://www.saxproject.org +// Written by David Megginson +// NO WARRANTY! This class is in the public domain. +// $Id: ParserAdapter.java,v 1.16 2004/04/26 17:34:35 dmegginson Exp $ + +package org.xml.sax.helpers; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +import org.xml.sax.Parser; // deprecated +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.AttributeList; // deprecated +import org.xml.sax.EntityResolver; +import org.xml.sax.DTDHandler; +import org.xml.sax.DocumentHandler; // deprecated +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import org.xml.sax.XMLReader; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + + +/** + * Adapt a SAX1 Parser as a SAX2 XMLReader. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This class wraps a SAX1 {@link org.xml.sax.Parser Parser} + * and makes it act as a SAX2 {@link org.xml.sax.XMLReader XMLReader}, + * with feature, property, and Namespace support. Note + * that it is not possible to report {@link org.xml.sax.ContentHandler#skippedEntity + * skippedEntity} events, since SAX1 does not make that information available.

+ * + *

This adapter does not test for duplicate Namespace-qualified + * attribute names.

+ * + * @since SAX 2.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.helpers.XMLReaderAdapter + * @see org.xml.sax.XMLReader + * @see org.xml.sax.Parser + */ +public class ParserAdapter implements XMLReader, DocumentHandler +{ + + + //////////////////////////////////////////////////////////////////// + // Constructors. + //////////////////////////////////////////////////////////////////// + + + /** + * Construct a new parser adapter. + * + *

Use the "org.xml.sax.parser" property to locate the + * embedded SAX1 driver.

+ * + * @exception SAXException If the embedded driver + * cannot be instantiated or if the + * org.xml.sax.parser property is not specified. + */ + public ParserAdapter () + throws SAXException + { + super(); + + String driver = System.getProperty("org.xml.sax.parser"); + + try { + setup(ParserFactory.makeParser()); + } catch (ClassNotFoundException e1) { + throw new + SAXException("Cannot find SAX1 driver class " + + driver, e1); + } catch (IllegalAccessException e2) { + throw new + SAXException("SAX1 driver class " + + driver + + " found but cannot be loaded", e2); + } catch (InstantiationException e3) { + throw new + SAXException("SAX1 driver class " + + driver + + " loaded but cannot be instantiated", e3); + } catch (ClassCastException e4) { + throw new + SAXException("SAX1 driver class " + + driver + + " does not implement org.xml.sax.Parser"); + } catch (NullPointerException e5) { + throw new + SAXException("System property org.xml.sax.parser not specified"); + } + } + + + /** + * Construct a new parser adapter. + * + *

Note that the embedded parser cannot be changed once the + * adapter is created; to embed a different parser, allocate + * a new ParserAdapter.

+ * + * @param parser The SAX1 parser to embed. + * @exception java.lang.NullPointerException If the parser parameter + * is null. + */ + public ParserAdapter (Parser parser) + { + super(); + setup(parser); + } + + + /** + * Internal setup method. + * + * @param parser The embedded parser. + * @exception java.lang.NullPointerException If the parser parameter + * is null. + */ + private void setup (Parser parser) + { + if (parser == null) { + throw new + NullPointerException("Parser argument must not be null"); + } + this.parser = parser; + atts = new AttributesImpl(); + nsSupport = new NamespaceSupport(); + attAdapter = new AttributeListAdapter(); + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.XMLReader. + //////////////////////////////////////////////////////////////////// + + + // + // Internal constants for the sake of convenience. + // + private final static String FEATURES = "http://xml.org/sax/features/"; + private final static String NAMESPACES = FEATURES + "namespaces"; + private final static String NAMESPACE_PREFIXES = FEATURES + "namespace-prefixes"; + private final static String XMLNS_URIs = FEATURES + "xmlns-uris"; + + + /** + * Set a feature flag for the parser. + * + *

The only features recognized are namespaces and + * namespace-prefixes.

+ * + * @param name The feature name, as a complete URI. + * @param value The requested feature value. + * @exception SAXNotRecognizedException If the feature + * can't be assigned or retrieved. + * @exception SAXNotSupportedException If the feature + * can't be assigned that value. + * @see org.xml.sax.XMLReader#setFeature + */ + @Override + public void setFeature (String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if (name.equals(NAMESPACES)) { + checkNotParsing("feature", name); + namespaces = value; + if (!namespaces && !prefixes) { + prefixes = true; + } + } else if (name.equals(NAMESPACE_PREFIXES)) { + checkNotParsing("feature", name); + prefixes = value; + if (!prefixes && !namespaces) { + namespaces = true; + } + } else if (name.equals(XMLNS_URIs)) { + checkNotParsing("feature", name); + uris = value; + } else { + throw new SAXNotRecognizedException("Feature: " + name); + } + } + + + /** + * Check a parser feature flag. + * + *

The only features recognized are namespaces and + * namespace-prefixes.

+ * + * @param name The feature name, as a complete URI. + * @return The current feature value. + * @exception SAXNotRecognizedException If the feature + * value can't be assigned or retrieved. + * @exception SAXNotSupportedException If the + * feature is not currently readable. + * @see org.xml.sax.XMLReader#setFeature + */ + @Override + public boolean getFeature (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if (name.equals(NAMESPACES)) { + return namespaces; + } else if (name.equals(NAMESPACE_PREFIXES)) { + return prefixes; + } else if (name.equals(XMLNS_URIs)) { + return uris; + } else { + throw new SAXNotRecognizedException("Feature: " + name); + } + } + + + /** + * Set a parser property. + * + *

No properties are currently recognized.

+ * + * @param name The property name. + * @param value The property value. + * @exception SAXNotRecognizedException If the property + * value can't be assigned or retrieved. + * @exception SAXNotSupportedException If the property + * can't be assigned that value. + * @see org.xml.sax.XMLReader#setProperty + */ + @Override + public void setProperty (String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + throw new SAXNotRecognizedException("Property: " + name); + } + + + /** + * Get a parser property. + * + *

No properties are currently recognized.

+ * + * @param name The property name. + * @return The property value. + * @exception SAXNotRecognizedException If the property + * value can't be assigned or retrieved. + * @exception SAXNotSupportedException If the property + * value is not currently readable. + * @see org.xml.sax.XMLReader#getProperty + */ + @Override + public Object getProperty (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + throw new SAXNotRecognizedException("Property: " + name); + } + + + /** + * Set the entity resolver. + * + * @param resolver The new entity resolver. + * @see org.xml.sax.XMLReader#setEntityResolver + */ + @Override + public void setEntityResolver (EntityResolver resolver) + { + entityResolver = resolver; + } + + + /** + * Return the current entity resolver. + * + * @return The current entity resolver, or null if none was supplied. + * @see org.xml.sax.XMLReader#getEntityResolver + */ + @Override + public EntityResolver getEntityResolver () + { + return entityResolver; + } + + + /** + * Set the DTD handler. + * + * @param handler the new DTD handler + * @see org.xml.sax.XMLReader#setEntityResolver + */ + @Override + public void setDTDHandler (DTDHandler handler) + { + dtdHandler = handler; + } + + + /** + * Return the current DTD handler. + * + * @return the current DTD handler, or null if none was supplied + * @see org.xml.sax.XMLReader#getEntityResolver + */ + @Override + public DTDHandler getDTDHandler () + { + return dtdHandler; + } + + + /** + * Set the content handler. + * + * @param handler the new content handler + * @see org.xml.sax.XMLReader#setEntityResolver + */ + @Override + public void setContentHandler (ContentHandler handler) + { + contentHandler = handler; + } + + + /** + * Return the current content handler. + * + * @return The current content handler, or null if none was supplied. + * @see org.xml.sax.XMLReader#getEntityResolver + */ + @Override + public ContentHandler getContentHandler () + { + return contentHandler; + } + + + /** + * Set the error handler. + * + * @param handler The new error handler. + * @see org.xml.sax.XMLReader#setEntityResolver + */ + @Override + public void setErrorHandler (ErrorHandler handler) + { + errorHandler = handler; + } + + + /** + * Return the current error handler. + * + * @return The current error handler, or null if none was supplied. + * @see org.xml.sax.XMLReader#getEntityResolver + */ + @Override + public ErrorHandler getErrorHandler () + { + return errorHandler; + } + + + /** + * Parse an XML document. + * + * @param systemId The absolute URL of the document. + * @exception java.io.IOException If there is a problem reading + * the raw content of the document. + * @exception SAXException If there is a problem + * processing the document. + * @see #parse(org.xml.sax.InputSource) + * @see org.xml.sax.Parser#parse(java.lang.String) + */ + @Override + public void parse (String systemId) + throws IOException, SAXException + { + parse(new InputSource(systemId)); + } + + + /** + * Parse an XML document. + * + * @param input An input source for the document. + * @exception java.io.IOException If there is a problem reading + * the raw content of the document. + * @exception SAXException If there is a problem + * processing the document. + * @see #parse(java.lang.String) + * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource) + */ + @Override + public void parse (InputSource input) + throws IOException, SAXException + { + if (parsing) { + throw new SAXException("Parser is already in use"); + } + setupParser(); + parsing = true; + try { + parser.parse(input); + } finally { + parsing = false; + } + parsing = false; + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.DocumentHandler. + //////////////////////////////////////////////////////////////////// + + + /** + * Adapter implementation method; do not call. + * Adapt a SAX1 document locator event. + * + * @param locator A document locator. + * @see org.xml.sax.ContentHandler#setDocumentLocator + */ + @Override + public void setDocumentLocator (Locator locator) + { + this.locator = locator; + if (contentHandler != null) { + contentHandler.setDocumentLocator(locator); + } + } + + + /** + * Adapter implementation method; do not call. + * Adapt a SAX1 start document event. + * + * @exception SAXException The client may raise a + * processing exception. + * @see org.xml.sax.DocumentHandler#startDocument + */ + @Override + public void startDocument () + throws SAXException + { + if (contentHandler != null) { + contentHandler.startDocument(); + } + } + + + /** + * Adapter implementation method; do not call. + * Adapt a SAX1 end document event. + * + * @exception SAXException The client may raise a + * processing exception. + * @see org.xml.sax.DocumentHandler#endDocument + */ + @Override + public void endDocument () + throws SAXException + { + if (contentHandler != null) { + contentHandler.endDocument(); + } + } + + + /** + * Adapter implementation method; do not call. + * Adapt a SAX1 startElement event. + * + *

If necessary, perform Namespace processing.

+ * + * @param qName The qualified (prefixed) name. + * @param qAtts The XML attribute list (with qnames). + * @exception SAXException The client may raise a + * processing exception. + */ + @Override + public void startElement (String qName, AttributeList qAtts) + throws SAXException + { + // These are exceptions from the + // first pass; they should be + // ignored if there's a second pass, + // but reported otherwise. + Vector exceptions = null; + + // If we're not doing Namespace + // processing, dispatch this quickly. + if (!namespaces) { + if (contentHandler != null) { + attAdapter.setAttributeList(qAtts); + contentHandler.startElement("", "", qName.intern(), + attAdapter); + } + return; + } + + + // OK, we're doing Namespace processing. + nsSupport.pushContext(); + int length = qAtts.getLength(); + + // First pass: handle NS decls + for (int i = 0; i < length; i++) { + String attQName = qAtts.getName(i); + + if (!attQName.startsWith("xmlns")) + continue; + // Could be a declaration... + String prefix; + int n = attQName.indexOf(':'); + + // xmlns=... + if (n == -1 && attQName.length () == 5) { + prefix = ""; + } else if (n != 5) { + // XML namespaces spec doesn't discuss "xmlnsf:oo" + // (and similarly named) attributes ... at most, warn + continue; + } else // xmlns:foo=... + prefix = attQName.substring(n+1); + + String value = qAtts.getValue(i); + if (!nsSupport.declarePrefix(prefix, value)) { + reportError("Illegal Namespace prefix: " + prefix); + continue; + } + if (contentHandler != null) + contentHandler.startPrefixMapping(prefix, value); + } + + // Second pass: copy all relevant + // attributes into the SAX2 AttributeList + // using updated prefix bindings + atts.clear(); + for (int i = 0; i < length; i++) { + String attQName = qAtts.getName(i); + String type = qAtts.getType(i); + String value = qAtts.getValue(i); + + // Declaration? + if (attQName.startsWith("xmlns")) { + String prefix; + int n = attQName.indexOf(':'); + + if (n == -1 && attQName.length () == 5) { + prefix = ""; + } else if (n != 5) { + // XML namespaces spec doesn't discuss "xmlnsf:oo" + // (and similarly named) attributes ... ignore + prefix = null; + } else { + prefix = attQName.substring(6); + } + // Yes, decl: report or prune + if (prefix != null) { + if (prefixes) { + if (uris) + // note funky case: localname can be null + // when declaring the default prefix, and + // yet the uri isn't null. + atts.addAttribute (nsSupport.XMLNS, prefix, + attQName.intern(), type, value); + else + atts.addAttribute ("", "", + attQName.intern(), type, value); + } + continue; + } + } + + // Not a declaration -- report + try { + String attName[] = processName(attQName, true, true); + atts.addAttribute(attName[0], attName[1], attName[2], + type, value); + } catch (SAXException e) { + if (exceptions == null) + exceptions = new Vector(); + exceptions.addElement(e); + atts.addAttribute("", attQName, attQName, type, value); + } + } + + // now handle the deferred exception reports + if (exceptions != null && errorHandler != null) { + for (int i = 0; i < exceptions.size(); i++) + errorHandler.error((SAXParseException) + (exceptions.elementAt(i))); + } + + // OK, finally report the event. + if (contentHandler != null) { + String name[] = processName(qName, false, false); + contentHandler.startElement(name[0], name[1], name[2], atts); + } + } + + + /** + * Adapter implementation method; do not call. + * Adapt a SAX1 end element event. + * + * @param qName The qualified (prefixed) name. + * @exception SAXException The client may raise a + * processing exception. + * @see org.xml.sax.DocumentHandler#endElement + */ + @Override + public void endElement (String qName) + throws SAXException + { + // If we're not doing Namespace + // processing, dispatch this quickly. + if (!namespaces) { + if (contentHandler != null) { + contentHandler.endElement("", "", qName.intern()); + } + return; + } + + // Split the name. + String names[] = processName(qName, false, false); + if (contentHandler != null) { + contentHandler.endElement(names[0], names[1], names[2]); + Enumeration prefixes = nsSupport.getDeclaredPrefixes(); + while (prefixes.hasMoreElements()) { + String prefix = (String)prefixes.nextElement(); + contentHandler.endPrefixMapping(prefix); + } + } + nsSupport.popContext(); + } + + + /** + * Adapter implementation method; do not call. + * Adapt a SAX1 characters event. + * + * @param ch An array of characters. + * @param start The starting position in the array. + * @param length The number of characters to use. + * @exception SAXException The client may raise a + * processing exception. + * @see org.xml.sax.DocumentHandler#characters + */ + @Override + public void characters (char ch[], int start, int length) + throws SAXException + { + if (contentHandler != null) { + contentHandler.characters(ch, start, length); + } + } + + + /** + * Adapter implementation method; do not call. + * Adapt a SAX1 ignorable whitespace event. + * + * @param ch An array of characters. + * @param start The starting position in the array. + * @param length The number of characters to use. + * @exception SAXException The client may raise a + * processing exception. + * @see org.xml.sax.DocumentHandler#ignorableWhitespace + */ + @Override + public void ignorableWhitespace (char ch[], int start, int length) + throws SAXException + { + if (contentHandler != null) { + contentHandler.ignorableWhitespace(ch, start, length); + } + } + + + /** + * Adapter implementation method; do not call. + * Adapt a SAX1 processing instruction event. + * + * @param target The processing instruction target. + * @param data The remainder of the processing instruction + * @exception SAXException The client may raise a + * processing exception. + * @see org.xml.sax.DocumentHandler#processingInstruction + */ + @Override + public void processingInstruction (String target, String data) + throws SAXException + { + if (contentHandler != null) { + contentHandler.processingInstruction(target, data); + } + } + + + + //////////////////////////////////////////////////////////////////// + // Internal utility methods. + //////////////////////////////////////////////////////////////////// + + + /** + * Initialize the parser before each run. + */ + private void setupParser () + { + // catch an illegal "nonsense" state. + if (!prefixes && !namespaces) + throw new IllegalStateException (); + + nsSupport.reset(); + if (uris) + nsSupport.setNamespaceDeclUris (true); + + if (entityResolver != null) { + parser.setEntityResolver(entityResolver); + } + if (dtdHandler != null) { + parser.setDTDHandler(dtdHandler); + } + if (errorHandler != null) { + parser.setErrorHandler(errorHandler); + } + parser.setDocumentHandler(this); + locator = null; + } + + + /** + * Process a qualified (prefixed) name. + * + *

If the name has an undeclared prefix, use only the qname + * and make an ErrorHandler.error callback in case the app is + * interested.

+ * + * @param qName The qualified (prefixed) name. + * @param isAttribute true if this is an attribute name. + * @return The name split into three parts. + * @exception SAXException The client may throw + * an exception if there is an error callback. + */ + private String [] processName (String qName, boolean isAttribute, + boolean useException) + throws SAXException + { + String parts[] = nsSupport.processName(qName, nameParts, + isAttribute); + if (parts == null) { + if (useException) + throw makeException("Undeclared prefix: " + qName); + reportError("Undeclared prefix: " + qName); + parts = new String[3]; + parts[0] = parts[1] = ""; + parts[2] = qName.intern(); + } + return parts; + } + + + /** + * Report a non-fatal error. + * + * @param message The error message. + * @exception SAXException The client may throw + * an exception. + */ + void reportError (String message) + throws SAXException + { + if (errorHandler != null) + errorHandler.error(makeException(message)); + } + + + /** + * Construct an exception for the current context. + * + * @param message The error message. + */ + private SAXParseException makeException (String message) + { + if (locator != null) { + return new SAXParseException(message, locator); + } else { + return new SAXParseException(message, null, null, -1, -1); + } + } + + + /** + * Throw an exception if we are parsing. + * + *

Use this method to detect illegal feature or + * property changes.

+ * + * @param type The type of thing (feature or property). + * @param name The feature or property name. + * @exception SAXNotSupportedException If a + * document is currently being parsed. + */ + private void checkNotParsing (String type, String name) + throws SAXNotSupportedException + { + if (parsing) { + throw new SAXNotSupportedException("Cannot change " + + type + ' ' + + name + " while parsing"); + + } + } + + + + //////////////////////////////////////////////////////////////////// + // Internal state. + //////////////////////////////////////////////////////////////////// + + private NamespaceSupport nsSupport; + private AttributeListAdapter attAdapter; + + private boolean parsing = false; + private String nameParts[] = new String[3]; + + private Parser parser = null; + + private AttributesImpl atts = null; + + // Features + private boolean namespaces = true; + private boolean prefixes = false; + private boolean uris = false; + + // Properties + + // Handlers + Locator locator; + + EntityResolver entityResolver = null; + DTDHandler dtdHandler = null; + ContentHandler contentHandler = null; + ErrorHandler errorHandler = null; + + + + //////////////////////////////////////////////////////////////////// + // Inner class to wrap an AttributeList when not doing NS proc. + //////////////////////////////////////////////////////////////////// + + + /** + * Adapt a SAX1 AttributeList as a SAX2 Attributes object. + * + *

This class is in the Public Domain, and comes with NO + * WARRANTY of any kind.

+ * + *

This wrapper class is used only when Namespace support + * is disabled -- it provides pretty much a direct mapping + * from SAX1 to SAX2, except that names and types are + * interned whenever requested.

+ */ + final class AttributeListAdapter implements Attributes + { + + /** + * Construct a new adapter. + */ + AttributeListAdapter () + { + } + + + /** + * Set the embedded AttributeList. + * + *

This method must be invoked before any of the others + * can be used.

+ * + * @param The SAX1 attribute list (with qnames). + */ + void setAttributeList (AttributeList qAtts) + { + this.qAtts = qAtts; + } + + + /** + * Return the length of the attribute list. + * + * @return The number of attributes in the list. + * @see org.xml.sax.Attributes#getLength + */ + @Override + public int getLength () + { + return qAtts.getLength(); + } + + + /** + * Return the Namespace URI of the specified attribute. + * + * @param The attribute's index. + * @return Always the empty string. + * @see org.xml.sax.Attributes#getURI + */ + @Override + public String getURI (int i) + { + return ""; + } + + + /** + * Return the local name of the specified attribute. + * + * @param The attribute's index. + * @return Always the empty string. + * @see org.xml.sax.Attributes#getLocalName + */ + @Override + public String getLocalName (int i) + { + return ""; + } + + + /** + * Return the qualified (prefixed) name of the specified attribute. + * + * @param The attribute's index. + * @return The attribute's qualified name, internalized. + */ + @Override + public String getQName (int i) + { + return qAtts.getName(i).intern(); + } + + + /** + * Return the type of the specified attribute. + * + * @param The attribute's index. + * @return The attribute's type as an internalized string. + */ + @Override + public String getType (int i) + { + return qAtts.getType(i).intern(); + } + + + /** + * Return the value of the specified attribute. + * + * @param The attribute's index. + * @return The attribute's value. + */ + @Override + public String getValue (int i) + { + return qAtts.getValue(i); + } + + + /** + * Look up an attribute index by Namespace name. + * + * @param uri The Namespace URI or the empty string. + * @param localName The local name. + * @return The attributes index, or -1 if none was found. + * @see org.xml.sax.Attributes#getIndex(java.lang.String,java.lang.String) + */ + @Override + public int getIndex (String uri, String localName) + { + return -1; + } + + + /** + * Look up an attribute index by qualified (prefixed) name. + * + * @param qName The qualified name. + * @return The attributes index, or -1 if none was found. + * @see org.xml.sax.Attributes#getIndex(java.lang.String) + */ + @Override + public int getIndex (String qName) + { + int max = atts.getLength(); + for (int i = 0; i < max; i++) { + if (qAtts.getName(i).equals(qName)) { + return i; + } + } + return -1; + } + + + /** + * Look up the type of an attribute by Namespace name. + * + * @param uri The Namespace URI + * @param localName The local name. + * @return The attribute's type as an internalized string. + */ + @Override + public String getType (String uri, String localName) + { + return null; + } + + + /** + * Look up the type of an attribute by qualified (prefixed) name. + * + * @param qName The qualified name. + * @return The attribute's type as an internalized string. + */ + @Override + public String getType (String qName) + { + return qAtts.getType(qName).intern(); + } + + + /** + * Look up the value of an attribute by Namespace name. + * + * @param uri The Namespace URI + * @param localName The local name. + * @return The attribute's value. + */ + @Override + public String getValue (String uri, String localName) + { + return null; + } + + + /** + * Look up the value of an attribute by qualified (prefixed) name. + * + * @param qName The qualified name. + * @return The attribute's value. + */ + @Override + public String getValue (String qName) + { + return qAtts.getValue(qName); + } + + private AttributeList qAtts; + } +} + +// end of ParserAdapter.java diff --git a/src/org/xml/sax/helpers/ParserFactory.java b/src/org/xml/sax/helpers/ParserFactory.java new file mode 100644 index 0000000..8ca7838 --- /dev/null +++ b/src/org/xml/sax/helpers/ParserFactory.java @@ -0,0 +1,123 @@ +// SAX parser factory. +// http://www.saxproject.org +// No warranty; no copyright -- use this as you will. +// $Id: ParserFactory.java,v 1.7 2002/01/30 20:52:36 dbrownell Exp $ + +package org.xml.sax.helpers; + +import org.xml.sax.Parser; + + +/** + * Java-specific class for dynamically loading SAX parsers. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

Note: This class is designed to work with the now-deprecated + * SAX1 {@link org.xml.sax.Parser Parser} class. SAX2 applications should use + * {@link org.xml.sax.helpers.XMLReaderFactory XMLReaderFactory} instead.

+ * + *

ParserFactory is not part of the platform-independent definition + * of SAX; it is an additional convenience class designed + * specifically for Java XML application writers. SAX applications + * can use the static methods in this class to allocate a SAX parser + * dynamically at run-time based either on the value of the + * `org.xml.sax.parser' system property or on a string containing the class + * name.

+ * + *

Note that the application still requires an XML parser that + * implements SAX1.

+ * + * @deprecated This class works with the deprecated + * {@link org.xml.sax.Parser Parser} + * interface. + * @since SAX 1.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + */ +public class ParserFactory { + + + /** + * Private null constructor. + */ + private ParserFactory () + { + } + + + /** + * Create a new SAX parser using the `org.xml.sax.parser' system property. + * + *

The named class must exist and must implement the + * {@link org.xml.sax.Parser Parser} interface.

+ * + * @exception java.lang.NullPointerException There is no value + * for the `org.xml.sax.parser' system property. + * @exception java.lang.ClassNotFoundException The SAX parser + * class was not found (check your CLASSPATH). + * @exception IllegalAccessException The SAX parser class was + * found, but you do not have permission to load + * it. + * @exception InstantiationException The SAX parser class was + * found but could not be instantiated. + * @exception java.lang.ClassCastException The SAX parser class + * was found and instantiated, but does not implement + * org.xml.sax.Parser. + * @see #makeParser(java.lang.String) + * @see org.xml.sax.Parser + */ + public static Parser makeParser () + throws ClassNotFoundException, + IllegalAccessException, + InstantiationException, + NullPointerException, + ClassCastException + { + String className = System.getProperty("org.xml.sax.parser"); + if (className == null) { + throw new NullPointerException("No value for sax.parser property"); + } else { + return makeParser(className); + } + } + + + /** + * Create a new SAX parser object using the class name provided. + * + *

The named class must exist and must implement the + * {@link org.xml.sax.Parser Parser} interface.

+ * + * @param className A string containing the name of the + * SAX parser class. + * @exception java.lang.ClassNotFoundException The SAX parser + * class was not found (check your CLASSPATH). + * @exception IllegalAccessException The SAX parser class was + * found, but you do not have permission to load + * it. + * @exception InstantiationException The SAX parser class was + * found but could not be instantiated. + * @exception java.lang.ClassCastException The SAX parser class + * was found and instantiated, but does not implement + * org.xml.sax.Parser. + * @see #makeParser() + * @see org.xml.sax.Parser + */ + public static Parser makeParser (String className) + throws ClassNotFoundException, + IllegalAccessException, + InstantiationException, + ClassCastException + { + return (Parser) NewInstance.newInstance ( + NewInstance.getClassLoader (), className); + } + +} + diff --git a/src/org/xml/sax/helpers/XMLFilterImpl.java b/src/org/xml/sax/helpers/XMLFilterImpl.java new file mode 100644 index 0000000..6f329d9 --- /dev/null +++ b/src/org/xml/sax/helpers/XMLFilterImpl.java @@ -0,0 +1,746 @@ +// XMLFilterImpl.java - base SAX2 filter implementation. +// http://www.saxproject.org +// Written by David Megginson +// NO WARRANTY! This class is in the Public Domain. +// $Id: XMLFilterImpl.java,v 1.9 2004/04/26 17:34:35 dmegginson Exp $ + +package org.xml.sax.helpers; + +import java.io.IOException; + +import org.xml.sax.XMLReader; +import org.xml.sax.XMLFilter; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.Attributes; +import org.xml.sax.EntityResolver; +import org.xml.sax.DTDHandler; +import org.xml.sax.ContentHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXNotRecognizedException; + + +/** + * Base class for deriving an XML filter. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This class is designed to sit between an {@link org.xml.sax.XMLReader + * XMLReader} and the client application's event handlers. By default, it + * does nothing but pass requests up to the reader and events + * on to the handlers unmodified, but subclasses can override + * specific methods to modify the event stream or the configuration + * requests as they pass through.

+ * + * @since SAX 2.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.XMLFilter + * @see org.xml.sax.XMLReader + * @see org.xml.sax.EntityResolver + * @see org.xml.sax.DTDHandler + * @see org.xml.sax.ContentHandler + * @see org.xml.sax.ErrorHandler + */ +public class XMLFilterImpl + implements XMLFilter, EntityResolver, DTDHandler, ContentHandler, ErrorHandler +{ + + + //////////////////////////////////////////////////////////////////// + // Constructors. + //////////////////////////////////////////////////////////////////// + + + /** + * Construct an empty XML filter, with no parent. + * + *

This filter will have no parent: you must assign a parent + * before you start a parse or do any configuration with + * setFeature or setProperty, unless you use this as a pure event + * consumer rather than as an {@link XMLReader}.

+ * + * @see org.xml.sax.XMLReader#setFeature + * @see org.xml.sax.XMLReader#setProperty + * @see #setParent + */ + public XMLFilterImpl () + { + super(); + } + + + /** + * Construct an XML filter with the specified parent. + * + * @see #setParent + * @see #getParent + */ + public XMLFilterImpl (XMLReader parent) + { + super(); + setParent(parent); + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.XMLFilter. + //////////////////////////////////////////////////////////////////// + + + /** + * Set the parent reader. + * + *

This is the {@link org.xml.sax.XMLReader XMLReader} from which + * this filter will obtain its events and to which it will pass its + * configuration requests. The parent may itself be another filter.

+ * + *

If there is no parent reader set, any attempt to parse + * or to set or get a feature or property will fail.

+ * + * @param parent The parent XML reader. + * @see #getParent + */ + @Override + public void setParent (XMLReader parent) + { + this.parent = parent; + } + + + /** + * Get the parent reader. + * + * @return The parent XML reader, or null if none is set. + * @see #setParent + */ + @Override + public XMLReader getParent () + { + return parent; + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.XMLReader. + //////////////////////////////////////////////////////////////////// + + + /** + * Set the value of a feature. + * + *

This will always fail if the parent is null.

+ * + * @param name The feature name. + * @param value The requested feature value. + * @exception org.xml.sax.SAXNotRecognizedException If the feature + * value can't be assigned or retrieved from the parent. + * @exception org.xml.sax.SAXNotSupportedException When the + * parent recognizes the feature name but + * cannot set the requested value. + */ + @Override + public void setFeature (String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if (parent != null) { + parent.setFeature(name, value); + } else { + throw new SAXNotRecognizedException("Feature: " + name); + } + } + + + /** + * Look up the value of a feature. + * + *

This will always fail if the parent is null.

+ * + * @param name The feature name. + * @return The current value of the feature. + * @exception org.xml.sax.SAXNotRecognizedException If the feature + * value can't be assigned or retrieved from the parent. + * @exception org.xml.sax.SAXNotSupportedException When the + * parent recognizes the feature name but + * cannot determine its value at this time. + */ + @Override + public boolean getFeature (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if (parent != null) { + return parent.getFeature(name); + } else { + throw new SAXNotRecognizedException("Feature: " + name); + } + } + + + /** + * Set the value of a property. + * + *

This will always fail if the parent is null.

+ * + * @param name The property name. + * @param value The requested property value. + * @exception org.xml.sax.SAXNotRecognizedException If the property + * value can't be assigned or retrieved from the parent. + * @exception org.xml.sax.SAXNotSupportedException When the + * parent recognizes the property name but + * cannot set the requested value. + */ + @Override + public void setProperty (String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if (parent != null) { + parent.setProperty(name, value); + } else { + throw new SAXNotRecognizedException("Property: " + name); + } + } + + + /** + * Look up the value of a property. + * + * @param name The property name. + * @return The current value of the property. + * @exception org.xml.sax.SAXNotRecognizedException If the property + * value can't be assigned or retrieved from the parent. + * @exception org.xml.sax.SAXNotSupportedException When the + * parent recognizes the property name but + * cannot determine its value at this time. + */ + @Override + public Object getProperty (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if (parent != null) { + return parent.getProperty(name); + } else { + throw new SAXNotRecognizedException("Property: " + name); + } + } + + + /** + * Set the entity resolver. + * + * @param resolver The new entity resolver. + */ + @Override + public void setEntityResolver (EntityResolver resolver) + { + entityResolver = resolver; + } + + + /** + * Get the current entity resolver. + * + * @return The current entity resolver, or null if none was set. + */ + @Override + public EntityResolver getEntityResolver () + { + return entityResolver; + } + + + /** + * Set the DTD event handler. + * + * @param handler the new DTD handler + */ + @Override + public void setDTDHandler (DTDHandler handler) + { + dtdHandler = handler; + } + + + /** + * Get the current DTD event handler. + * + * @return The current DTD handler, or null if none was set. + */ + @Override + public DTDHandler getDTDHandler () + { + return dtdHandler; + } + + + /** + * Set the content event handler. + * + * @param handler the new content handler + */ + @Override + public void setContentHandler (ContentHandler handler) + { + contentHandler = handler; + } + + + /** + * Get the content event handler. + * + * @return The current content handler, or null if none was set. + */ + @Override + public ContentHandler getContentHandler () + { + return contentHandler; + } + + + /** + * Set the error event handler. + * + * @param handler the new error handler + */ + @Override + public void setErrorHandler (ErrorHandler handler) + { + errorHandler = handler; + } + + + /** + * Get the current error event handler. + * + * @return The current error handler, or null if none was set. + */ + @Override + public ErrorHandler getErrorHandler () + { + return errorHandler; + } + + + /** + * Parse a document. + * + * @param input The input source for the document entity. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @exception java.io.IOException An IO exception from the parser, + * possibly from a byte stream or character stream + * supplied by the application. + */ + @Override + public void parse (InputSource input) + throws SAXException, IOException + { + setupParse(); + parent.parse(input); + } + + + /** + * Parse a document. + * + * @param systemId The system identifier as a fully-qualified URI. + * @exception org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * @exception java.io.IOException An IO exception from the parser, + * possibly from a byte stream or character stream + * supplied by the application. + */ + @Override + public void parse (String systemId) + throws SAXException, IOException + { + parse(new InputSource(systemId)); + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.EntityResolver. + //////////////////////////////////////////////////////////////////// + + + /** + * Filter an external entity resolution. + * + * @param publicId The entity's public identifier, or null. + * @param systemId The entity's system identifier. + * @return A new InputSource or null for the default. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + * @exception java.io.IOException The client may throw an + * I/O-related exception while obtaining the + * new InputSource. + */ + @Override + public InputSource resolveEntity (String publicId, String systemId) + throws SAXException, IOException + { + if (entityResolver != null) { + return entityResolver.resolveEntity(publicId, systemId); + } else { + return null; + } + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.DTDHandler. + //////////////////////////////////////////////////////////////////// + + + /** + * Filter a notation declaration event. + * + * @param name The notation name. + * @param publicId The notation's public identifier, or null. + * @param systemId The notation's system identifier, or null. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + if (dtdHandler != null) { + dtdHandler.notationDecl(name, publicId, systemId); + } + } + + + /** + * Filter an unparsed entity declaration event. + * + * @param name The entity name. + * @param publicId The entity's public identifier, or null. + * @param systemId The entity's system identifier, or null. + * @param notationName The name of the associated notation. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void unparsedEntityDecl (String name, String publicId, + String systemId, String notationName) + throws SAXException + { + if (dtdHandler != null) { + dtdHandler.unparsedEntityDecl(name, publicId, systemId, + notationName); + } + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.ContentHandler. + //////////////////////////////////////////////////////////////////// + + + /** + * Filter a new document locator event. + * + * @param locator The document locator. + */ + @Override + public void setDocumentLocator (Locator locator) + { + this.locator = locator; + if (contentHandler != null) { + contentHandler.setDocumentLocator(locator); + } + } + + + /** + * Filter a start document event. + * + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void startDocument () + throws SAXException + { + if (contentHandler != null) { + contentHandler.startDocument(); + } + } + + + /** + * Filter an end document event. + * + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void endDocument () + throws SAXException + { + if (contentHandler != null) { + contentHandler.endDocument(); + } + } + + + /** + * Filter a start Namespace prefix mapping event. + * + * @param prefix The Namespace prefix. + * @param uri The Namespace URI. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + if (contentHandler != null) { + contentHandler.startPrefixMapping(prefix, uri); + } + } + + + /** + * Filter an end Namespace prefix mapping event. + * + * @param prefix The Namespace prefix. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void endPrefixMapping (String prefix) + throws SAXException + { + if (contentHandler != null) { + contentHandler.endPrefixMapping(prefix); + } + } + + + /** + * Filter a start element event. + * + * @param uri The element's Namespace URI, or the empty string. + * @param localName The element's local name, or the empty string. + * @param qName The element's qualified (prefixed) name, or the empty + * string. + * @param atts The element's attributes. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void startElement (String uri, String localName, String qName, + Attributes atts) + throws SAXException + { + if (contentHandler != null) { + contentHandler.startElement(uri, localName, qName, atts); + } + } + + + /** + * Filter an end element event. + * + * @param uri The element's Namespace URI, or the empty string. + * @param localName The element's local name, or the empty string. + * @param qName The element's qualified (prefixed) name, or the empty + * string. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void endElement (String uri, String localName, String qName) + throws SAXException + { + if (contentHandler != null) { + contentHandler.endElement(uri, localName, qName); + } + } + + + /** + * Filter a character data event. + * + * @param ch An array of characters. + * @param start The starting position in the array. + * @param length The number of characters to use from the array. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void characters (char ch[], int start, int length) + throws SAXException + { + if (contentHandler != null) { + contentHandler.characters(ch, start, length); + } + } + + + /** + * Filter an ignorable whitespace event. + * + * @param ch An array of characters. + * @param start The starting position in the array. + * @param length The number of characters to use from the array. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void ignorableWhitespace (char ch[], int start, int length) + throws SAXException + { + if (contentHandler != null) { + contentHandler.ignorableWhitespace(ch, start, length); + } + } + + + /** + * Filter a processing instruction event. + * + * @param target The processing instruction target. + * @param data The text following the target. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void processingInstruction (String target, String data) + throws SAXException + { + if (contentHandler != null) { + contentHandler.processingInstruction(target, data); + } + } + + + /** + * Filter a skipped entity event. + * + * @param name The name of the skipped entity. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void skippedEntity (String name) + throws SAXException + { + if (contentHandler != null) { + contentHandler.skippedEntity(name); + } + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.ErrorHandler. + //////////////////////////////////////////////////////////////////// + + + /** + * Filter a warning event. + * + * @param e The warning as an exception. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void warning (SAXParseException e) + throws SAXException + { + if (errorHandler != null) { + errorHandler.warning(e); + } + } + + + /** + * Filter an error event. + * + * @param e The error as an exception. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void error (SAXParseException e) + throws SAXException + { + if (errorHandler != null) { + errorHandler.error(e); + } + } + + + /** + * Filter a fatal error event. + * + * @param e The error as an exception. + * @exception org.xml.sax.SAXException The client may throw + * an exception during processing. + */ + @Override + public void fatalError (SAXParseException e) + throws SAXException + { + if (errorHandler != null) { + errorHandler.fatalError(e); + } + } + + + + //////////////////////////////////////////////////////////////////// + // Internal methods. + //////////////////////////////////////////////////////////////////// + + + /** + * Set up before a parse. + * + *

Before every parse, check whether the parent is + * non-null, and re-register the filter for all of the + * events.

+ */ + private void setupParse () + { + if (parent == null) { + throw new NullPointerException("No parent for filter"); + } + parent.setEntityResolver(this); + parent.setDTDHandler(this); + parent.setContentHandler(this); + parent.setErrorHandler(this); + } + + + + //////////////////////////////////////////////////////////////////// + // Internal state. + //////////////////////////////////////////////////////////////////// + + private XMLReader parent = null; + private Locator locator = null; + private EntityResolver entityResolver = null; + private DTDHandler dtdHandler = null; + private ContentHandler contentHandler = null; + private ErrorHandler errorHandler = null; + +} + +// end of XMLFilterImpl.java diff --git a/src/org/xml/sax/helpers/XMLReaderAdapter.java b/src/org/xml/sax/helpers/XMLReaderAdapter.java new file mode 100644 index 0000000..8a587c4 --- /dev/null +++ b/src/org/xml/sax/helpers/XMLReaderAdapter.java @@ -0,0 +1,562 @@ +// XMLReaderAdapter.java - adapt an SAX2 XMLReader to a SAX1 Parser +// http://www.saxproject.org +// Written by David Megginson +// NO WARRANTY! This class is in the public domain. +// $Id: XMLReaderAdapter.java,v 1.9 2004/04/26 17:34:35 dmegginson Exp $ + +package org.xml.sax.helpers; + +import java.io.IOException; +import java.util.Locale; + +import org.xml.sax.Parser; // deprecated +import org.xml.sax.Locator; +import org.xml.sax.InputSource; +import org.xml.sax.AttributeList; // deprecated +import org.xml.sax.EntityResolver; +import org.xml.sax.DTDHandler; +import org.xml.sax.DocumentHandler; // deprecated +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; + +import org.xml.sax.XMLReader; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXNotSupportedException; + + +/** + * Adapt a SAX2 XMLReader as a SAX1 Parser. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This class wraps a SAX2 {@link org.xml.sax.XMLReader XMLReader} + * and makes it act as a SAX1 {@link org.xml.sax.Parser Parser}. The XMLReader + * must support a true value for the + * http://xml.org/sax/features/namespace-prefixes property or parsing will fail + * with a {@link org.xml.sax.SAXException SAXException}; if the XMLReader + * supports a false value for the http://xml.org/sax/features/namespaces + * property, that will also be used to improve efficiency.

+ * + * @since SAX 2.0 + * @author David Megginson + * @version 2.0.1 (sax2r2) + * @see org.xml.sax.Parser + * @see org.xml.sax.XMLReader + */ +public class XMLReaderAdapter implements Parser, ContentHandler +{ + + + //////////////////////////////////////////////////////////////////// + // Constructor. + //////////////////////////////////////////////////////////////////// + + + /** + * Create a new adapter. + * + *

Use the "org.xml.sax.driver" property to locate the SAX2 + * driver to embed.

+ * + * @exception org.xml.sax.SAXException If the embedded driver + * cannot be instantiated or if the + * org.xml.sax.driver property is not specified. + */ + public XMLReaderAdapter () + throws SAXException + { + setup(XMLReaderFactory.createXMLReader()); + } + + + /** + * Create a new adapter. + * + *

Create a new adapter, wrapped around a SAX2 XMLReader. + * The adapter will make the XMLReader act like a SAX1 + * Parser.

+ * + * @param xmlReader The SAX2 XMLReader to wrap. + * @exception java.lang.NullPointerException If the argument is null. + */ + public XMLReaderAdapter (XMLReader xmlReader) + { + setup(xmlReader); + } + + + + /** + * Internal setup. + * + * @param xmlReader The embedded XMLReader. + */ + private void setup (XMLReader xmlReader) + { + if (xmlReader == null) { + throw new NullPointerException("XMLReader must not be null"); + } + this.xmlReader = xmlReader; + qAtts = new AttributesAdapter(); + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.Parser. + //////////////////////////////////////////////////////////////////// + + + /** + * Set the locale for error reporting. + * + *

This is not supported in SAX2, and will always throw + * an exception.

+ * + * @param locale the locale for error reporting. + * @see org.xml.sax.Parser#setLocale + * @exception org.xml.sax.SAXException Thrown unless overridden. + */ + @Override + public void setLocale (Locale locale) + throws SAXException + { + throw new SAXNotSupportedException("setLocale not supported"); + } + + + /** + * Register the entity resolver. + * + * @param resolver The new resolver. + * @see org.xml.sax.Parser#setEntityResolver + */ + @Override + public void setEntityResolver (EntityResolver resolver) + { + xmlReader.setEntityResolver(resolver); + } + + + /** + * Register the DTD event handler. + * + * @param handler The new DTD event handler. + * @see org.xml.sax.Parser#setDTDHandler + */ + @Override + public void setDTDHandler (DTDHandler handler) + { + xmlReader.setDTDHandler(handler); + } + + + /** + * Register the SAX1 document event handler. + * + *

Note that the SAX1 document handler has no Namespace + * support.

+ * + * @param handler The new SAX1 document event handler. + * @see org.xml.sax.Parser#setDocumentHandler + */ + @Override + public void setDocumentHandler (DocumentHandler handler) + { + documentHandler = handler; + } + + + /** + * Register the error event handler. + * + * @param handler The new error event handler. + * @see org.xml.sax.Parser#setErrorHandler + */ + @Override + public void setErrorHandler (ErrorHandler handler) + { + xmlReader.setErrorHandler(handler); + } + + + /** + * Parse the document. + * + *

This method will throw an exception if the embedded + * XMLReader does not support the + * http://xml.org/sax/features/namespace-prefixes property.

+ * + * @param systemId The absolute URL of the document. + * @exception java.io.IOException If there is a problem reading + * the raw content of the document. + * @exception org.xml.sax.SAXException If there is a problem + * processing the document. + * @see #parse(org.xml.sax.InputSource) + * @see org.xml.sax.Parser#parse(java.lang.String) + */ + @Override + public void parse (String systemId) + throws IOException, SAXException + { + parse(new InputSource(systemId)); + } + + + /** + * Parse the document. + * + *

This method will throw an exception if the embedded + * XMLReader does not support the + * http://xml.org/sax/features/namespace-prefixes property.

+ * + * @param input An input source for the document. + * @exception java.io.IOException If there is a problem reading + * the raw content of the document. + * @exception org.xml.sax.SAXException If there is a problem + * processing the document. + * @see #parse(java.lang.String) + * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource) + */ + @Override + public void parse (InputSource input) + throws IOException, SAXException + { + setupXMLReader(); + xmlReader.parse(input); + } + + + /** + * Set up the XML reader. + */ + private void setupXMLReader () + throws SAXException + { + xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); + try { + xmlReader.setFeature("http://xml.org/sax/features/namespaces", + false); + } catch (SAXException e) { + // NO OP: it's just extra information, and we can ignore it + } + xmlReader.setContentHandler(this); + } + + + + //////////////////////////////////////////////////////////////////// + // Implementation of org.xml.sax.ContentHandler. + //////////////////////////////////////////////////////////////////// + + + /** + * Set a document locator. + * + * @param locator The document locator. + * @see org.xml.sax.ContentHandler#setDocumentLocator + */ + @Override + public void setDocumentLocator (Locator locator) + { + if (documentHandler != null) + documentHandler.setDocumentLocator(locator); + } + + + /** + * Start document event. + * + * @exception org.xml.sax.SAXException The client may raise a + * processing exception. + * @see org.xml.sax.ContentHandler#startDocument + */ + @Override + public void startDocument () + throws SAXException + { + if (documentHandler != null) + documentHandler.startDocument(); + } + + + /** + * End document event. + * + * @exception org.xml.sax.SAXException The client may raise a + * processing exception. + * @see org.xml.sax.ContentHandler#endDocument + */ + @Override + public void endDocument () + throws SAXException + { + if (documentHandler != null) + documentHandler.endDocument(); + } + + + /** + * Adapt a SAX2 start prefix mapping event. + * + * @param prefix The prefix being mapped. + * @param uri The Namespace URI being mapped to. + * @see org.xml.sax.ContentHandler#startPrefixMapping + */ + @Override + public void startPrefixMapping (String prefix, String uri) + { + } + + + /** + * Adapt a SAX2 end prefix mapping event. + * + * @param prefix The prefix being mapped. + * @see org.xml.sax.ContentHandler#endPrefixMapping + */ + @Override + public void endPrefixMapping (String prefix) + { + } + + + /** + * Adapt a SAX2 start element event. + * + * @param uri The Namespace URI. + * @param localName The Namespace local name. + * @param qName The qualified (prefixed) name. + * @param atts The SAX2 attributes. + * @exception org.xml.sax.SAXException The client may raise a + * processing exception. + * @see org.xml.sax.ContentHandler#endDocument + */ + @Override + public void startElement (String uri, String localName, + String qName, Attributes atts) + throws SAXException + { + if (documentHandler != null) { + qAtts.setAttributes(atts); + documentHandler.startElement(qName, qAtts); + } + } + + + /** + * Adapt a SAX2 end element event. + * + * @param uri The Namespace URI. + * @param localName The Namespace local name. + * @param qName The qualified (prefixed) name. + * @exception org.xml.sax.SAXException The client may raise a + * processing exception. + * @see org.xml.sax.ContentHandler#endElement + */ + @Override + public void endElement (String uri, String localName, + String qName) + throws SAXException + { + if (documentHandler != null) + documentHandler.endElement(qName); + } + + + /** + * Adapt a SAX2 characters event. + * + * @param ch An array of characters. + * @param start The starting position in the array. + * @param length The number of characters to use. + * @exception org.xml.sax.SAXException The client may raise a + * processing exception. + * @see org.xml.sax.ContentHandler#characters + */ + @Override + public void characters (char ch[], int start, int length) + throws SAXException + { + if (documentHandler != null) + documentHandler.characters(ch, start, length); + } + + + /** + * Adapt a SAX2 ignorable whitespace event. + * + * @param ch An array of characters. + * @param start The starting position in the array. + * @param length The number of characters to use. + * @exception org.xml.sax.SAXException The client may raise a + * processing exception. + * @see org.xml.sax.ContentHandler#ignorableWhitespace + */ + @Override + public void ignorableWhitespace (char ch[], int start, int length) + throws SAXException + { + if (documentHandler != null) + documentHandler.ignorableWhitespace(ch, start, length); + } + + + /** + * Adapt a SAX2 processing instruction event. + * + * @param target The processing instruction target. + * @param data The remainder of the processing instruction + * @exception org.xml.sax.SAXException The client may raise a + * processing exception. + * @see org.xml.sax.ContentHandler#processingInstruction + */ + @Override + public void processingInstruction (String target, String data) + throws SAXException + { + if (documentHandler != null) + documentHandler.processingInstruction(target, data); + } + + + /** + * Adapt a SAX2 skipped entity event. + * + * @param name The name of the skipped entity. + * @see org.xml.sax.ContentHandler#skippedEntity + * @exception org.xml.sax.SAXException Throwable by subclasses. + */ + @Override + public void skippedEntity (String name) + throws SAXException + { + } + + + + //////////////////////////////////////////////////////////////////// + // Internal state. + //////////////////////////////////////////////////////////////////// + + XMLReader xmlReader; + DocumentHandler documentHandler; + AttributesAdapter qAtts; + + + + //////////////////////////////////////////////////////////////////// + // Internal class. + //////////////////////////////////////////////////////////////////// + + + /** + * Internal class to wrap a SAX2 Attributes object for SAX1. + */ + final class AttributesAdapter implements AttributeList + { + AttributesAdapter () + { + } + + + /** + * Set the embedded Attributes object. + * + * @param The embedded SAX2 Attributes. + */ + void setAttributes (Attributes attributes) + { + this.attributes = attributes; + } + + + /** + * Return the number of attributes. + * + * @return The length of the attribute list. + * @see org.xml.sax.AttributeList#getLength + */ + @Override + public int getLength () + { + return attributes.getLength(); + } + + + /** + * Return the qualified (prefixed) name of an attribute by position. + * + * @return The qualified name. + * @see org.xml.sax.AttributeList#getName + */ + @Override + public String getName (int i) + { + return attributes.getQName(i); + } + + + /** + * Return the type of an attribute by position. + * + * @return The type. + * @see org.xml.sax.AttributeList#getType(int) + */ + @Override + public String getType (int i) + { + return attributes.getType(i); + } + + + /** + * Return the value of an attribute by position. + * + * @return The value. + * @see org.xml.sax.AttributeList#getValue(int) + */ + @Override + public String getValue (int i) + { + return attributes.getValue(i); + } + + + /** + * Return the type of an attribute by qualified (prefixed) name. + * + * @return The type. + * @see org.xml.sax.AttributeList#getType(java.lang.String) + */ + @Override + public String getType (String qName) + { + return attributes.getType(qName); + } + + + /** + * Return the value of an attribute by qualified (prefixed) name. + * + * @return The value. + * @see org.xml.sax.AttributeList#getValue(java.lang.String) + */ + @Override + public String getValue (String qName) + { + return attributes.getValue(qName); + } + + private Attributes attributes; + } + +} + +// end of XMLReaderAdapter.java diff --git a/src/org/xml/sax/helpers/XMLReaderFactory.java b/src/org/xml/sax/helpers/XMLReaderFactory.java new file mode 100644 index 0000000..f50be7a --- /dev/null +++ b/src/org/xml/sax/helpers/XMLReaderFactory.java @@ -0,0 +1,202 @@ +// XMLReaderFactory.java - factory for creating a new reader. +// http://www.saxproject.org +// Written by David Megginson +// and by David Brownell +// NO WARRANTY! This class is in the Public Domain. +// $Id: XMLReaderFactory.java,v 1.10 2002/04/22 01:00:13 dbrownell Exp $ + +package org.xml.sax.helpers; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import org.xml.sax.XMLReader; +import org.xml.sax.SAXException; + + +/** + * Factory for creating an XML reader. + * + *
+ * This module, both source code and documentation, is in the + * Public Domain, and comes with NO WARRANTY. + * See http://www.saxproject.org + * for further information. + *
+ * + *

This class contains static methods for creating an XML reader + * from an explicit class name, or based on runtime defaults:

+ * + *
+ * try {
+ *   XMLReader myReader = XMLReaderFactory.createXMLReader();
+ * } catch (SAXException e) {
+ *   System.err.println(e.getMessage());
+ * }
+ * 
+ * + *

Note to Distributions bundled with parsers: + * You should modify the implementation of the no-arguments + * createXMLReader to handle cases where the external + * configuration mechanisms aren't set up. That method should do its + * best to return a parser when one is in the class path, even when + * nothing bound its class name to org.xml.sax.driver so + * those configuration mechanisms would see it.

+ * + * @since SAX 2.0 + * @author David Megginson, David Brownell + * @version 2.0.1 (sax2r2) + */ +final public class XMLReaderFactory +{ + /** + * Private constructor. + * + *

This constructor prevents the class from being instantiated.

+ */ + private XMLReaderFactory () + { + } + + private static final String property = "org.xml.sax.driver"; + + /** + * Attempt to create an XMLReader from system defaults. + * In environments which can support it, the name of the XMLReader + * class is determined by trying each these options in order, and + * using the first one which succeeds:

    + * + *
  • If the system property org.xml.sax.driver + * has a value, that is used as an XMLReader class name.
  • + * + *
  • The JAR "Services API" is used to look for a class name + * in the META-INF/services/org.xml.sax.driver file in + * jarfiles available to the runtime.
  • + * + *
  • SAX parser distributions are strongly encouraged to provide + * a default XMLReader class name that will take effect only when + * previous options (on this list) are not successful.
  • + * + *
  • Finally, if {@link ParserFactory#makeParser()} can + * return a system default SAX1 parser, that parser is wrapped in + * a {@link ParserAdapter}. (This is a migration aid for SAX1 + * environments, where the org.xml.sax.parser system + * property will often be usable.)
  • + * + *
+ * + *

In environments such as small embedded systems, which can not + * support that flexibility, other mechanisms to determine the default + * may be used.

+ * + *

Note that many Java environments allow system properties to be + * initialized on a command line. This means that in most cases + * setting a good value for that property ensures that calls to this + * method will succeed, except when security policies intervene. + * This will also maximize application portability to older SAX + * environments, with less robust implementations of this method. + *

+ * + * @return A new XMLReader. + * @exception org.xml.sax.SAXException If no default XMLReader class + * can be identified and instantiated. + * @see #createXMLReader(java.lang.String) + */ + public static XMLReader createXMLReader () + throws SAXException + { + String className = null; + ClassLoader loader = NewInstance.getClassLoader (); + + // 1. try the JVM-instance-wide system property + try { className = System.getProperty (property); } + catch (RuntimeException e) { /* normally fails for applets */ } + + // 2. if that fails, try META-INF/services/ + if (className == null) { + try { + String service = "META-INF/services/" + property; + InputStream in; + BufferedReader reader; + + if (loader == null) + in = ClassLoader.getSystemResourceAsStream (service); + else + in = loader.getResourceAsStream (service); + + if (in != null) { + reader = new BufferedReader ( + new InputStreamReader (in, "UTF8")); + className = reader.readLine (); + in.close (); + } + } catch (Exception e) { + } + } + + // 3. Distro-specific fallback + if (className == null) { +// BEGIN DISTRIBUTION-SPECIFIC + + // EXAMPLE: + // className = "com.example.sax.XmlReader"; + // or a $JAVA_HOME/jre/lib/*properties setting... + +// END DISTRIBUTION-SPECIFIC + } + + // do we know the XMLReader implementation class yet? + if (className != null) + return loadClass (loader, className); + + // 4. panic -- adapt any SAX1 parser + try { + return new ParserAdapter (ParserFactory.makeParser ()); + } catch (Exception e) { + throw new SAXException ("Can't create default XMLReader; " + + "is system property org.xml.sax.driver set?"); + } + } + + + /** + * Attempt to create an XML reader from a class name. + * + *

Given a class name, this method attempts to load + * and instantiate the class as an XML reader.

+ * + *

Note that this method will not be usable in environments where + * the caller (perhaps an applet) is not permitted to load classes + * dynamically.

+ * + * @return A new XML reader. + * @exception org.xml.sax.SAXException If the class cannot be + * loaded, instantiated, and cast to XMLReader. + * @see #createXMLReader() + */ + public static XMLReader createXMLReader (String className) + throws SAXException + { + return loadClass (NewInstance.getClassLoader (), className); + } + + private static XMLReader loadClass (ClassLoader loader, String className) + throws SAXException + { + try { + return (XMLReader) NewInstance.newInstance (loader, className); + } catch (ClassNotFoundException e1) { + throw new SAXException("SAX2 driver class " + className + + " not found", e1); + } catch (IllegalAccessException e2) { + throw new SAXException("SAX2 driver class " + className + + " found but cannot be loaded", e2); + } catch (InstantiationException e3) { + throw new SAXException("SAX2 driver class " + className + + " loaded but cannot be instantiated (no empty public constructor?)", + e3); + } catch (ClassCastException e4) { + throw new SAXException("SAX2 driver class " + className + + " does not implement XMLReader", e4); + } + } +} diff --git a/src/org/xml/sax/helpers/package.html b/src/org/xml/sax/helpers/package.html new file mode 100644 index 0000000..8f323c0 --- /dev/null +++ b/src/org/xml/sax/helpers/package.html @@ -0,0 +1,11 @@ + + + + +

This package contains "helper" classes, including +support for bootstrapping SAX-based applications. + +

See http://www.saxproject.org +for more information about SAX.

+ +