summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/awt/Color.java33
-rw-r--r--java/awt/Component.java8
-rw-r--r--java/awt/Container.java36
-rw-r--r--java/awt/MenuShortcut.java233
-rw-r--r--java/awt/dnd/DropTargetDragEvent.java3
-rw-r--r--java/awt/image/AffineTransformOp.java373
-rw-r--r--java/awt/image/BandCombineOp.java114
-rw-r--r--java/awt/image/ColorConvertOp.java443
-rw-r--r--java/awt/image/ColorModel.java2
-rw-r--r--java/awt/image/ComponentColorModel.java22
-rw-r--r--java/awt/image/ConvolveOp.java128
-rw-r--r--java/io/File.java76
-rw-r--r--java/io/FileDescriptor.java5
-rw-r--r--java/io/InputStreamReader.java60
-rw-r--r--java/io/ObjectInputStream.java99
-rw-r--r--java/io/ObjectOutputStream.java355
-rw-r--r--java/io/ObjectStreamClass.java443
-rw-r--r--java/io/ObjectStreamField.java2
-rw-r--r--java/io/PrintStream.java2
-rw-r--r--java/lang/management/ManagementFactory.java43
-rw-r--r--java/lang/ref/Reference.java13
-rw-r--r--java/lang/ref/ReferenceQueue.java57
-rw-r--r--java/math/BigInteger.java60
-rw-r--r--java/net/SocketPermission.java61
-rw-r--r--java/security/AlgorithmParameterGenerator.java100
-rw-r--r--java/security/AlgorithmParameters.java122
-rw-r--r--java/security/KeyFactory.java99
-rw-r--r--java/security/KeyPairGenerator.java91
-rw-r--r--java/security/KeyStore.java132
-rw-r--r--java/security/MessageDigest.java109
-rw-r--r--java/security/SecureClassLoader.java52
-rw-r--r--java/security/SecureRandom.java126
-rw-r--r--java/security/Signature.java105
-rw-r--r--java/security/cert/CertPathBuilder.java113
-rw-r--r--java/security/cert/CertPathValidator.java103
-rw-r--r--java/security/cert/CertStore.java115
-rw-r--r--java/security/cert/CertificateFactory.java126
-rw-r--r--java/util/Calendar.java33
-rw-r--r--java/util/Locale.java48
-rw-r--r--java/util/ResourceBundle.java134
-rw-r--r--java/util/Vector.java12
-rw-r--r--java/util/regex/Matcher.java26
-rw-r--r--java/util/zip/ZipFile.java109
43 files changed, 2695 insertions, 1731 deletions
diff --git a/java/awt/Color.java b/java/awt/Color.java
index b03129241..c3d04c049 100644
--- a/java/awt/Color.java
+++ b/java/awt/Color.java
@@ -534,14 +534,31 @@ public class Color implements Paint, Serializable
{
// Do not inline getRGB() to this.value, because of SystemColor.
int value = getRGB();
- int red = (value & RED_MASK) >> 16;
- int green = (value & GREEN_MASK) >> 8;
- int blue = value & BLUE_MASK;
- // We have to special case 0-2 because they won't scale by division.
- red = red < 3 ? 3 : (int) Math.min(255, red / BRIGHT_SCALE);
- green = green < 3 ? 3 : (int) Math.min(255, green / BRIGHT_SCALE);
- blue = blue < 3 ? 3 : (int) Math.min(255, blue / BRIGHT_SCALE);
- return new Color(red, green, blue, 255);
+ int[] hues = new int[3];
+ hues[0] = (value & RED_MASK) >> 16;
+ hues[1] = (value & GREEN_MASK) >> 8;
+ hues[2] = value & BLUE_MASK;
+
+ // (0,0,0) is a special case.
+ if (hues[0] == 0 && hues[1] == 0 && hues[2] ==0)
+ {
+ hues[0] = 3;
+ hues[1] = 3;
+ hues[2] = 3;
+ }
+ else
+ {
+ for (int index = 0; index < 3; index++)
+ {
+
+ if (hues[index] > 2)
+ hues[index] = (int) Math.min(255, hues[index]/0.7f);
+ if (hues[index] == 1 || hues[index] == 2)
+ hues[index] = 4;
+ }
+ }
+
+ return new Color(hues[0], hues[1], hues[2], 255);
}
/**
diff --git a/java/awt/Component.java b/java/awt/Component.java
index ba669f8ec..26ba605b5 100644
--- a/java/awt/Component.java
+++ b/java/awt/Component.java
@@ -579,7 +579,7 @@ public abstract class Component
transient ComponentPeer peer;
/** The preferred component orientation. */
- transient ComponentOrientation orientation = ComponentOrientation.UNKNOWN;
+ transient ComponentOrientation componentOrientation = ComponentOrientation.UNKNOWN;
/**
* The associated graphics configuration.
@@ -5244,8 +5244,8 @@ p * <li>the set of backward traversal keys
public void setComponentOrientation(ComponentOrientation o)
{
- ComponentOrientation oldOrientation = orientation;
- orientation = o;
+ ComponentOrientation oldOrientation = componentOrientation;
+ componentOrientation = o;
firePropertyChange("componentOrientation", oldOrientation, o);
}
@@ -5257,7 +5257,7 @@ p * <li>the set of backward traversal keys
*/
public ComponentOrientation getComponentOrientation()
{
- return orientation;
+ return componentOrientation;
}
/**
diff --git a/java/awt/Container.java b/java/awt/Container.java
index e6d8493d3..17ca3e0ad 100644
--- a/java/awt/Container.java
+++ b/java/awt/Container.java
@@ -87,8 +87,6 @@ public class Container extends Component
Component[] component;
LayoutManager layoutMgr;
- Dimension maxSize;
-
/**
* @since 1.4
*/
@@ -653,45 +651,39 @@ public class Container extends Component
return;
ContainerPeer cPeer = null;
- if (peer != null && ! (peer instanceof LightweightPeer))
+ if (peer instanceof ContainerPeer)
{
cPeer = (ContainerPeer) peer;
cPeer.beginValidate();
}
- for (int i = 0; i < ncomponents; ++i)
- {
- Component comp = component[i];
-
- if (comp.getPeer () == null)
- comp.addNotify();
- }
-
doLayout ();
for (int i = 0; i < ncomponents; ++i)
{
Component comp = component[i];
- if (! comp.isValid())
+ if (comp instanceof Container && ! (comp instanceof Window)
+ && ! comp.valid)
{
- if (comp instanceof Container)
- {
- ((Container) comp).validateTree();
- }
- else
- {
- component[i].validate();
- }
+ ((Container) comp).validateTree();
+ }
+ else
+ {
+ comp.validate();
}
}
+ if (peer instanceof ContainerPeer)
+ {
+ cPeer = (ContainerPeer) peer;
+ cPeer.endValidate();
+ }
+
/* children will call invalidate() when they are layed out. It
is therefore important that valid is not set to true
until after the children have been layed out. */
valid = true;
- if (cPeer != null)
- cPeer.endValidate();
}
public void setFont(Font f)
diff --git a/java/awt/MenuShortcut.java b/java/awt/MenuShortcut.java
index adfd1d318..259cbf1ae 100644
--- a/java/awt/MenuShortcut.java
+++ b/java/awt/MenuShortcut.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package java.awt;
+import java.awt.event.KeyEvent;
+
/**
* This class implements a keyboard accelerator for a menu item.
*
@@ -70,6 +72,8 @@ private int key;
*/
private boolean usesShift;
+private String keyName;
+
/*************************************************************************/
/**
@@ -99,6 +103,7 @@ MenuShortcut(int key, boolean usesShift)
{
this.key = key;
this.usesShift = usesShift;
+ setKeyName(key);
}
/*************************************************************************/
@@ -181,7 +186,11 @@ equals(Object obj)
public String
toString()
{
- return(getClass().getName() + "[" + paramString () + "]");
+ String temp = "Ctrl+";
+ if (usesShift)
+ temp = temp + "Shift+";
+ temp = temp + keyName;
+ return temp;
}
public int
@@ -204,4 +213,224 @@ paramString()
return "key=" + key + ",usesShift=" + usesShift;
}
-} // class MenuShortcut
+private void
+setKeyName(int key)
+{
+ if (key == '\n')
+ keyName = "Enter";
+ else if (key == '\b')
+ keyName = "Backspace";
+ else if (key == '\t')
+ keyName = "Tab";
+ else if (key == ' ')
+ keyName = "Space";
+ else if (key == ',')
+ keyName = "Comma";
+ else if (key == '.')
+ keyName = "Period";
+ else if (key == '/')
+ keyName = "Slash";
+ else if (key == '\\')
+ keyName = "Back Slash";
+ else if (key == ';')
+ keyName = "Semicolon";
+ else if (key == '=')
+ keyName = "Equals";
+ else if (key == '[')
+ keyName = "Open Bracket";
+ else if (key == ']')
+ keyName = "Close Bracket";
+ else if (key == '0')
+ keyName = "0";
+ else if (key == '1')
+ keyName = "1";
+ else if (key == '2')
+ keyName = "2";
+ else if (key == '3')
+ keyName = "3";
+ else if (key == '4')
+ keyName = "4";
+ else if (key == '5')
+ keyName = "5";
+ else if (key == '6')
+ keyName = "6";
+ else if (key == '7')
+ keyName = "7";
+ else if (key == '8')
+ keyName = "8";
+ else if (key == '9')
+ keyName = "9";
+ else if (key == 'A')
+ keyName = "A";
+ else if (key == 'B')
+ keyName = "B";
+ else if (key == 'C')
+ keyName = "C";
+ else if (key == 'D')
+ keyName = "D";
+ else if (key == 'E')
+ keyName = "E";
+ else if (key == 'F')
+ keyName = "F";
+ else if (key == 'G')
+ keyName = "G";
+ else if (key == 'H')
+ keyName = "H";
+ else if (key == 'I')
+ keyName = "I";
+ else if (key == 'J')
+ keyName = "J";
+ else if (key == 'K')
+ keyName = "K";
+ else if (key == 'L')
+ keyName = "L";
+ else if (key == 'M')
+ keyName = "M";
+ else if (key == 'N')
+ keyName = "N";
+ else if (key == 'O')
+ keyName = "O";
+ else if (key == 'P')
+ keyName = "P";
+ else if (key == 'Q')
+ keyName = "Q";
+ else if (key == 'R')
+ keyName = "R";
+ else if (key == 'S')
+ keyName = "S";
+ else if (key == 'T')
+ keyName = "T";
+ else if (key == 'U')
+ keyName = "U";
+ else if (key == 'V')
+ keyName = "V";
+ else if (key == 'W')
+ keyName = "W";
+ else if (key == 'X')
+ keyName = "X";
+ else if (key == 'Y')
+ keyName = "Y";
+ else if (key == 'Z')
+ keyName = "Z";
+ else if (key == 3)
+ keyName = "Cancel";
+ else if (key == 12)
+ keyName = "Clear";
+ else if (key == 16)
+ keyName = "Shift";
+ else if (key == 17)
+ keyName = "Ctrl";
+ else if (key == 18)
+ keyName = "Alt";
+ else if (key == 19)
+ keyName = "Pause";
+ else if (key == 20)
+ keyName = "Caps Lock";
+ else if (key == 21)
+ keyName = "Kana";
+ else if (key == 24)
+ keyName = "Final";
+ else if (key == 25)
+ keyName = "Kanji";
+ else if (key == 27)
+ keyName = "Escape";
+ else if (key == 28)
+ keyName = "Convert";
+ else if (key == 29)
+ keyName = "No Convert";
+ else if (key == 30)
+ keyName = "Accept";
+ else if (key == 31)
+ keyName = "Mode Change";
+ else if (key == 33)
+ keyName = "Page Up";
+ else if (key == 34)
+ keyName = "Page Down";
+ else if (key == 35)
+ keyName = "End";
+ else if (key == 36)
+ keyName = "Home";
+ else if (key == 37)
+ keyName = "Left";
+ else if (key == 38)
+ keyName = "Up";
+ else if (key == 39)
+ keyName = "Right";
+ else if (key == 40)
+ keyName = "Down";
+ else if (key == 96)
+ keyName = "NumPad-0";
+ else if (key == 97)
+ keyName = "NumPad-1";
+ else if (key == 98)
+ keyName = "NumPad-2";
+ else if (key == 99)
+ keyName = "NumPad-3";
+ else if (key == 100)
+ keyName = "NumPad-4";
+ else if (key == 101)
+ keyName = "NumPad-5";
+ else if (key == 102)
+ keyName = "NumPad-6";
+ else if (key == 103)
+ keyName = "NumPad-7";
+ else if (key == 104)
+ keyName = "NumPad-8";
+ else if (key == 105)
+ keyName = "NumPad-9";
+ else if (key == 106)
+ keyName = "NumPad *";
+ else if (key == 107)
+ keyName = "NumPad +";
+ else if (key == 108)
+ keyName = "NumPad ,";
+ else if (key == 109)
+ keyName = "NumPad -";
+ else if (key == 110)
+ keyName = "NumPad .";
+ else if (key == 111)
+ keyName = "NumPad /";
+ else if (key == 112)
+ keyName = "F1";
+ else if (key == 113)
+ keyName = "F2";
+ else if (key == 114)
+ keyName = "F3";
+ else if (key == 115)
+ keyName = "F4";
+ else if (key == 116)
+ keyName = "F5";
+ else if (key == 117)
+ keyName = "F6";
+ else if (key == 118)
+ keyName = "F7";
+ else if (key == 119)
+ keyName = "F8";
+ else if (key == 120)
+ keyName = "F9";
+ else if (key == 121)
+ keyName = "F10";
+ else if (key == 122)
+ keyName = "F11";
+ else if (key == 123)
+ keyName = "F12";
+ else if (key == 127)
+ keyName = "Delete";
+ else if (key == 144)
+ keyName = "Num Lock";
+ else if (key == 145)
+ keyName = "Scroll Lock";
+ else if (key == 154)
+ keyName = "Print Screen";
+ else if (key == 155)
+ keyName = "Insert";
+ else if (key == 156)
+ keyName = "Help";
+ else if (key == 157)
+ keyName = "Meta";
+ else if (key == 192)
+ keyName = "Back Quote";
+ else if (key == 222)
+ keyName = "Quote";
+}
+} // class MenuShortcut
diff --git a/java/awt/dnd/DropTargetDragEvent.java b/java/awt/dnd/DropTargetDragEvent.java
index 838141ec3..58feb4387 100644
--- a/java/awt/dnd/DropTargetDragEvent.java
+++ b/java/awt/dnd/DropTargetDragEvent.java
@@ -147,7 +147,6 @@ public class DropTargetDragEvent extends DropTargetEvent
*/
public Transferable getTransferable()
{
- // FIXME: Not implemented
- return null;
+ return context.getTransferable();
}
} // class DropTargetDragEvent
diff --git a/java/awt/image/AffineTransformOp.java b/java/awt/image/AffineTransformOp.java
index bb4b79523..7820684d2 100644
--- a/java/awt/image/AffineTransformOp.java
+++ b/java/awt/image/AffineTransformOp.java
@@ -1,6 +1,6 @@
/* AffineTransformOp.java -- This class performs affine
transformation between two images or rasters in 2 dimensions.
- Copyright (C) 2004 Free Software Foundation
+ Copyright (C) 2004, 2006 Free Software Foundation
This file is part of GNU Classpath.
@@ -52,6 +52,7 @@ import java.util.Arrays;
* rasters in 2 dimensions.
*
* @author Olga Rodimina (rodimina@redhat.com)
+ * @author Francis Kung (fkung@redhat.com)
*/
public class AffineTransformOp implements BufferedImageOp, RasterOp
{
@@ -74,6 +75,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
*
* @param xform AffineTransform that will applied to the source image
* @param interpolationType type of interpolation used
+ * @throws ImagingOpException if the transform matrix is noninvertible
*/
public AffineTransformOp (AffineTransform xform, int interpolationType)
{
@@ -102,6 +104,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
*
* @param xform AffineTransform that will applied to the source image
* @param hints rendering hints that will be used during transformation
+ * @throws ImagingOpException if the transform matrix is noninvertible
*/
public AffineTransformOp (AffineTransform xform, RenderingHints hints)
{
@@ -115,8 +118,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
* Creates empty BufferedImage with the size equal to that of the
* transformed image and correct number of bands. The newly created
* image is created with the specified ColorModel.
- * If the ColorModel is equal to null, then image is created
- * with the ColorModel of the source image.
+ * If the ColorModel is equal to null, an appropriate ColorModel is used.
*
* @param src source image
* @param destCM color model for the destination image
@@ -125,17 +127,21 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
public BufferedImage createCompatibleDestImage (BufferedImage src,
ColorModel destCM)
{
+ if (destCM != null)
+ return new BufferedImage(destCM,
+ createCompatibleDestRaster(src.getRaster()),
+ src.isAlphaPremultiplied(), null);
+
+ // This behaviour was determined by Mauve testcases, and is compatible
+ // with the reference implementation
+ if (src.getType() == BufferedImage.TYPE_INT_ARGB_PRE
+ || src.getType() == BufferedImage.TYPE_4BYTE_ABGR
+ || src.getType() == BufferedImage.TYPE_4BYTE_ABGR_PRE)
+ return new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
- // if destCm is not specified, use color model of the source image
-
- if (destCM == null)
- destCM = src.getColorModel ();
-
- return new BufferedImage (destCM,
- createCompatibleDestRaster (src.getRaster ()),
- src.isAlphaPremultiplied (),
- null);
-
+ else
+ return new BufferedImage(src.getWidth(), src.getHeight(),
+ BufferedImage.TYPE_INT_ARGB);
}
/**
@@ -148,7 +154,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
*/
public WritableRaster createCompatibleDestRaster (Raster src)
{
- Rectangle rect = (Rectangle) getBounds2D (src);
+ Rectangle2D rect = getBounds2D(src);
// throw RasterFormatException if resulting width or height of the
// transformed raster is 0
@@ -156,33 +162,31 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
if (rect.getWidth () == 0 || rect.getHeight () == 0)
throw new RasterFormatException("width or height is 0");
- return src.createCompatibleWritableRaster ((int) rect.getWidth (),
- (int) rect.getHeight ());
+ return src.createCompatibleWritableRaster((int) rect.getWidth(),
+ (int) rect.getHeight());
}
/**
* Transforms source image using transform specified at the constructor.
- * The resulting transformed image is stored in the destination image.
+ * The resulting transformed image is stored in the destination image if one
+ * is provided; otherwise a new BufferedImage is created and returned.
*
* @param src source image
* @param dst destination image
+ * @throws IllegalArgumentException if the source and destination image are
+ * the same
* @return transformed source image
*/
public final BufferedImage filter (BufferedImage src, BufferedImage dst)
{
if (dst == src)
- throw new IllegalArgumentException ("src image cannot be the same as the dst image");
-
- // If the destination image is null, then BufferedImage is
- // created with ColorModel of the source image
+ throw new IllegalArgumentException ("src image cannot be the same as " +
+ "the dst image");
+ // If the destination image is null, then use a compatible BufferedImage
if (dst == null)
- dst = createCompatibleDestImage(src, src.getColorModel ());
-
- // FIXME: Must check if color models of src and dst images are the same.
- // If it is not, then source image should be converted to color model
- // of the destination image
+ dst = createCompatibleDestImage(src, null);
Graphics2D gr = (Graphics2D) dst.createGraphics ();
gr.setRenderingHints (hints);
@@ -193,10 +197,13 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
/**
* Transforms source raster using transform specified at the constructor.
- * The resulting raster is stored in the destination raster.
+ * The resulting raster is stored in the destination raster if it is not
+ * null, otherwise a new raster is created and returned.
*
* @param src source raster
* @param dst destination raster
+ * @throws IllegalArgumentException if the source and destination are not
+ * compatible
* @return transformed raster
*/
public final WritableRaster filter (Raster src, WritableRaster dst)
@@ -212,85 +219,47 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
throw new IllegalArgumentException("src and dst must have same number"
+ " of bands");
- double[] dpts = new double[dst.getWidth() * 2];
- double[] pts = new double[dst.getWidth() * 2];
+ // Create arrays to hold all the points
+ double[] dstPts = new double[dst.getHeight() * dst.getWidth() * 2];
+ double[] srcPts = new double[dst.getHeight() * dst.getWidth() * 2];
+
+ // Populate array with all points in the *destination* raster
+ int i = 0;
for (int x = 0; x < dst.getWidth(); x++)
- {
- dpts[2 * x] = x + dst.getMinX();
- dpts[2 * x + 1] = x;
- }
- Rectangle srcbounds = src.getBounds();
- if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
- {
- for (int y = dst.getMinY(); y < dst.getMinY() + dst.getHeight(); y++)
- {
- try {
- transform.inverseTransform(dpts, 0, pts, 0, dst.getWidth() * 2);
- } catch (NoninvertibleTransformException e) {
- // Can't happen since the constructor traps this
- e.printStackTrace();
- }
-
- for (int x = 0; x < dst.getWidth(); x++)
- {
- if (!srcbounds.contains(pts[2 * x], pts[2 * x + 1]))
- continue;
- dst.setDataElements(x + dst.getMinX(), y,
- src.getDataElements((int)pts[2 * x],
- (int)pts[2 * x + 1],
- null));
- }
- }
- }
- else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
- {
- double[] tmp = new double[4 * src.getNumBands()];
- for (int y = dst.getMinY(); y < dst.getMinY() + dst.getHeight(); y++)
{
- try {
- transform.inverseTransform(dpts, 0, pts, 0, dst.getWidth() * 2);
- } catch (NoninvertibleTransformException e) {
- // Can't happen since the constructor traps this
- e.printStackTrace();
- }
-
- for (int x = 0; x < dst.getWidth(); x++)
- {
- if (!srcbounds.contains(pts[2 * x], pts[2 * x + 1]))
- continue;
- int xx = (int)pts[2 * x];
- int yy = (int)pts[2 * x + 1];
- double dx = (pts[2 * x] - xx);
- double dy = (pts[2 * x + 1] - yy);
-
- // TODO write this more intelligently
- if (xx == src.getMinX() + src.getWidth() - 1 ||
- yy == src.getMinY() + src.getHeight() - 1)
+ for (int y = 0; y < dst.getHeight(); y++)
{
- // bottom or right edge
- Arrays.fill(tmp, 0);
- src.getPixel(xx, yy, tmp);
+ dstPts[i++] = x;
+ dstPts[i++] = y;
}
- else
- {
- // Normal case
- src.getPixels(xx, yy, 2, 2, tmp);
- for (int b = 0; b < src.getNumBands(); b++)
- tmp[b] = dx * dy * tmp[b]
- + (1 - dx) * dy * tmp[b + src.getNumBands()]
- + dx * (1 - dy) * tmp[b + 2 * src.getNumBands()]
- + (1 - dx) * (1 - dy) * tmp[b + 3 * src.getNumBands()];
- }
- dst.setPixel(x, y, tmp);
- }
}
- }
- else
- {
- // Bicubic
- throw new UnsupportedOperationException("not implemented yet");
- }
+ Rectangle srcbounds = src.getBounds();
+
+ // Use an inverse transform to map each point in the destination to
+ // a point in the source. Note that, while all points in the destination
+ // matrix are integers, this is not necessarily true for points in the
+ // source (hence why interpolation is required)
+ try
+ {
+ AffineTransform inverseTx = transform.createInverse();
+ inverseTx.transform(dstPts, 0, srcPts, 0, dstPts.length / 2);
+ }
+ catch (NoninvertibleTransformException e)
+ {
+ // Shouldn't happen since the constructor traps this
+ throw new ImagingOpException(e.getMessage());
+ }
+
+ // Different interpolation methods...
+ if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
+ filterNearest(src, dst, dstPts, srcPts);
+ else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
+ filterBilinear(src, dst, dstPts, srcPts);
+
+ else // bicubic
+ filterBicubic(src, dst, dstPts, srcPts);
+
return dst;
}
@@ -314,16 +283,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
*/
public final Rectangle2D getBounds2D (Raster src)
{
- // determine new size for the transformed raster.
- // Need to calculate transformed coordinates of the lower right
- // corner of the raster. The upper left corner is always (0,0)
-
- double x2 = (double) src.getWidth () + src.getMinX ();
- double y2 = (double) src.getHeight () + src.getMinY ();
- Point2D p2 = getPoint2D (new Point2D.Double (x2,y2), null);
-
- Rectangle2D rect = new Rectangle (0, 0, (int) p2.getX (), (int) p2.getY ());
- return rect.getBounds ();
+ return transform.createTransformedShape(src.getBounds()).getBounds2D();
}
/**
@@ -333,8 +293,12 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
*/
public final int getInterpolationType ()
{
- if(hints.containsValue (RenderingHints.VALUE_INTERPOLATION_BILINEAR))
+ if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
return TYPE_BILINEAR;
+
+ else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BICUBIC))
+ return TYPE_BICUBIC;
+
else
return TYPE_NEAREST_NEIGHBOR;
}
@@ -372,4 +336,191 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
{
return transform;
}
+
+ /**
+ * Perform nearest-neighbour filtering
+ *
+ * @param src the source raster
+ * @param dst the destination raster
+ * @param dpts array of points on the destination raster
+ * @param pts array of corresponding points on the source raster
+ */
+ private void filterNearest(Raster src, WritableRaster dst, double[] dpts,
+ double[] pts)
+ {
+ Rectangle srcbounds = src.getBounds();
+
+ // For all points on the destination raster, copy the value from the
+ // corrosponding (rounded) source point
+ for (int i = 0; i < dpts.length; i += 2)
+ {
+ int srcX = (int) Math.round(pts[i]) + src.getMinX();
+ int srcY = (int) Math.round(pts[i + 1]) + src.getMinY();
+
+ if (srcbounds.contains(srcX, srcY))
+ dst.setDataElements((int) dpts[i] + dst.getMinX(),
+ (int) dpts[i + 1] + dst.getMinY(),
+ src.getDataElements(srcX, srcY, null));
+ }
+ }
+
+ /**
+ * Perform bilinear filtering
+ *
+ * @param src the source raster
+ * @param dst the destination raster
+ * @param dpts array of points on the destination raster
+ * @param pts array of corresponding points on the source raster
+ */
+ private void filterBilinear(Raster src, WritableRaster dst, double[] dpts,
+ double[] pts)
+ {
+ Rectangle srcbounds = src.getBounds();
+
+ // For all points in the destination raster, use bilinear interpolation
+ // to find the value from the corrosponding source points
+ for (int i = 0; i < dpts.length; i += 2)
+ {
+ int srcX = (int) Math.round(pts[i]) + src.getMinX();
+ int srcY = (int) Math.round(pts[i + 1]) + src.getMinY();
+
+ if (srcbounds.contains(srcX, srcY))
+ {
+ // Corner case at the bottom or right edge; use nearest neighbour
+ if (pts[i] >= src.getWidth() - 1
+ || pts[i + 1] >= src.getHeight() - 1)
+ dst.setDataElements((int) dpts[i] + dst.getMinX(),
+ (int) dpts[i + 1] + dst.getMinY(),
+ src.getDataElements(srcX, srcY, null));
+
+ // Standard case, apply the bilinear formula
+ else
+ {
+ int x = (int) Math.floor(pts[i] + src.getMinX());
+ int y = (int) Math.floor(pts[i + 1] + src.getMinY());
+ double xdiff = pts[i] + src.getMinX() - x;
+ double ydiff = pts[i + 1] + src.getMinY() - y;
+
+ // Run the interpolation for each band
+ for (int j = 0; j < src.getNumBands(); j++)
+ {
+ double result = (src.getSampleDouble(x, y, j) * (1 - xdiff)
+ + src.getSampleDouble(x + 1, y, j) * xdiff)
+ * (1 - ydiff)
+ + (src.getSampleDouble(x, y + 1, j)
+ * (1 - xdiff)
+ + src.getSampleDouble(x + 1, y + 1, j)
+ * xdiff)
+ * ydiff;
+ dst.setSample((int) dpts[i] + dst.getMinX(),
+ (int) dpts[i + 1] + dst.getMinY(),
+ j, result);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Perform bicubic filtering
+ * based on http://local.wasp.uwa.edu.au/~pbourke/colour/bicubic/
+ *
+ * @param src the source raster
+ * @param dst the destination raster
+ * @param dpts array of points on the destination raster
+ * @param pts array of corresponding points on the source raster
+ */
+ private void filterBicubic(Raster src, WritableRaster dst, double[] dpts,
+ double[] pts)
+ {
+ Rectangle srcbounds = src.getBounds();
+
+ // For all points on the destination raster, perform bicubic interpolation
+ // from corrosponding source points
+ double[] result = new double[src.getNumBands()];
+ for (int i = 0; i < dpts.length; i += 2)
+ {
+ if (srcbounds.contains((int) Math.round(pts[i]) + src.getMinX(),
+ (int) Math.round(pts[i + 1]) + src.getMinY()))
+ {
+ int x = (int) Math.floor(pts[i] + src.getMinX());
+ int y = (int) Math.floor(pts[i + 1] + src.getMinY());
+ double dx = pts[i] + src.getMinX() - x;
+ double dy = pts[i + 1] + src.getMinY() - y;
+ Arrays.fill(result, 0);
+
+ for (int m = - 1; m < 3; m++)
+ {
+ for (int n = - 1; n < 3; n++)
+ {
+ // R(x) = ( P(x+2)^3 - 4 P(x+1)^3 + 6 P(x)^3 - 4 P(x-1)^3 ) / 6
+ double r1 = 0;
+ double r2 = 0;
+
+ // Calculate R(m - dx)
+ double rx = m - dx + 2;
+ if (rx > 0)
+ r1 += rx * rx * rx;
+
+ rx = m - dx + 1;
+ if (rx > 0)
+ r1 -= 4 * rx * rx * rx;
+
+ rx = m - dx;
+ if (rx > 0)
+ r1 += 6 * rx * rx * rx;
+
+ rx = m - dx - 1;
+ if (rx > 0)
+ r1 -= 4 * rx * rx * rx;
+
+ r1 /= 6;
+
+ // Calculate R(dy - n);
+ rx = dy - n + 2;
+ if (rx > 0)
+ r2 += rx * rx * rx;
+
+ rx = dy - n + 1;
+ if (rx > 0)
+ r2 -= 4 * rx * rx * rx;
+
+ rx = dy - n;
+ if (rx > 0)
+ r2 += 6 * rx * rx * rx;
+
+ rx = dy - n - 1;
+ if (rx > 0)
+ r2 -= 4 * rx * rx * rx;
+
+ r2 /= 6;
+
+ // Calculate F(i+m, j+n) R(m - dx) R(dy - n)
+ // Check corner cases
+ int srcX = x + m;
+ if (srcX >= src.getMinX() + src.getWidth())
+ srcX = src.getMinX() + src.getWidth() - 1;
+ else if (srcX < src.getMinX())
+ srcX = src.getMinX();
+
+ int srcY = y + n;
+ if (srcY >= src.getMinY() + src.getHeight())
+ srcY = src.getMinY() + src.getHeight() - 1;
+ else if (srcY < src.getMinY())
+ srcY = src.getMinY();
+
+ // Calculate once for each band
+ for (int j = 0; j < result.length; j++)
+ result[j] += src.getSample(srcX, srcY, j) * r1 * r2;
+ }
+ }
+
+ // Put it all together
+ for (int j = 0; j < result.length; j++)
+ dst.setSample((int) dpts[i] + dst.getMinX(),
+ (int) dpts[i + 1] + dst.getMinY(),
+ j, result[j]);
+ }
+ }
+ }
}
diff --git a/java/awt/image/BandCombineOp.java b/java/awt/image/BandCombineOp.java
index 634125ed2..c4e2d5810 100644
--- a/java/awt/image/BandCombineOp.java
+++ b/java/awt/image/BandCombineOp.java
@@ -1,4 +1,5 @@
-/* Copyright (C) 2004 Free Software Foundation
+/* BandCombineOp.java - perform a combination on the bands of a raster
+ Copyright (C) 2004, 2006 Free Software Foundation
This file is part of GNU Classpath.
@@ -36,7 +37,6 @@ exception statement from your version. */
package java.awt.image;
-import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
@@ -65,52 +65,66 @@ public class BandCombineOp implements RasterOp
*
* @param matrix The matrix to filter pixels with.
* @param hints Rendering hints to apply. Ignored.
+ * @throws ArrayIndexOutOfBoundsException if the matrix is invalid
*/
public BandCombineOp(float[][] matrix, RenderingHints hints)
{
- this.matrix = matrix;
+ this.matrix = new float[matrix.length][];
+ int width = matrix[0].length;
+ for (int i = 0; i < matrix.length; i++)
+ {
+ this.matrix[i] = new float[width + 1];
+ for (int j = 0; j < width; j++)
+ this.matrix[i][j] = matrix[i][j];
+
+ // The reference implementation pads the array with a trailing zero...
+ this.matrix[i][width] = 0;
+ }
+
this.hints = hints;
}
/**
- * Filter Raster pixels through a matrix.
- *
- * Applies the Op matrix to source pixes to produce dest pixels. Each row
- * of the matrix is multiplied by the src pixel components to produce the
- * dest pixel. If matrix is one more than the number of bands in the src,
- * the last element is implicitly multiplied by 1, i.e. added to the sum
- * for that dest component.
- *
- * If dest is null, a suitable Raster is created. This implementation uses
- * createCompatibleDestRaster.
+ * Filter Raster pixels through a matrix. Applies the Op matrix to source
+ * pixes to produce dest pixels. Each row of the matrix is multiplied by the
+ * src pixel components to produce the dest pixel. If matrix is one more than
+ * the number of bands in the src, the last element is implicitly multiplied
+ * by 1, i.e. added to the sum for that dest component. If dest is null, a
+ * suitable Raster is created. This implementation uses
+ * createCompatibleDestRaster.
*
* @param src The source Raster.
- * @param dest The destination Raster, or null.
- * @returns The destination Raster or an allocated Raster.
+ * @param dest The destination Raster, or null.
+ * @throws IllegalArgumentException if the destination raster is incompatible
+ * with the source raster.
+ * @return The filtered Raster.
* @see java.awt.image.RasterOp#filter(java.awt.image.Raster,
- *java.awt.image.WritableRaster)
+ * java.awt.image.WritableRaster)
*/
public WritableRaster filter(Raster src, WritableRaster dest) {
if (dest == null)
dest = createCompatibleDestRaster(src);
-
+ else if (dest.getNumBands() != src.getNumBands()
+ || dest.getTransferType() != src.getTransferType())
+ throw new IllegalArgumentException("Destination raster is incompatible with source raster");
+
// Filter the pixels
- float[] spix = new float[matrix[0].length];
+ float[] spix = new float[matrix[0].length - 1];
float[] dpix = new float[matrix.length];
for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++)
for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++)
- {
- // In case matrix rows have implicit translation
- spix[spix.length - 1] = 1.0f;
- src.getPixel(x, y, spix);
- for (int i = 0; i < matrix.length; i++)
{
- dpix[i] = 0;
- for (int j = 0; j < matrix[0].length; j++)
- dpix[i] += spix[j] * matrix[i][j];
+ // In case matrix rows have implicit translation
+ spix[spix.length - 1] = 1.0f;
+ src.getPixel(x, y, spix);
+ for (int i = 0; i < matrix.length; i++)
+ {
+ dpix[i] = 0;
+ for (int j = 0; j < matrix[0].length - 1; j++)
+ dpix[i] += spix[j] * matrix[i][j];
+ }
+ dest.setPixel(x, y, dpix);
}
- dest.setPixel(x, y, dpix);
- }
return dest;
}
@@ -125,28 +139,48 @@ public class BandCombineOp implements RasterOp
/**
* Creates a new WritableRaster that can be used as the destination for this
- * Op. This implementation creates a Banded Raster with data type FLOAT.
- * @see
- *java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster)
+ * Op. The number of bands in the source raster must equal the number of rows
+ * in the op matrix, which must also be equal to either the number of columns
+ * or (columns - 1) in the matrix.
+ *
+ * @param src The source raster.
+ * @return A compatible raster.
+ * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster)
+ * @throws IllegalArgumentException if the raster is incompatible with the
+ * matrix.
*/
public WritableRaster createCompatibleDestRaster(Raster src)
{
- return Raster.createBandedRaster(DataBuffer.TYPE_FLOAT, src.getWidth(),
- src.getHeight(), matrix.length,
- new Point(src.getMinX(), src.getMinY()));
+ // Destination raster must have same number of bands as source
+ if (src.getNumBands() != matrix.length)
+ throw new IllegalArgumentException("Number of rows in matrix specifies an "
+ + "incompatible number of bands");
+
+ // We use -1 and -2 because we previously padded the rows with a trailing 0
+ if (src.getNumBands() != matrix[0].length - 1
+ && src.getNumBands() != matrix[0].length - 2)
+ throw new IllegalArgumentException("Incompatible number of bands: "
+ + "the number of bands in the raster must equal the number of "
+ + "columns in the matrix, optionally minus one");
+
+ return src.createCompatibleWritableRaster();
}
- /** Return corresponding destination point for source point.
+ /**
+ * Return corresponding destination point for source point. Because this is
+ * not a geometric operation, it simply returns a copy of the source.
*
- * LookupOp will return the value of src unchanged.
* @param src The source point.
* @param dst The destination point.
+ * @return dst The destination point.
* @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D,
*java.awt.geom.Point2D)
*/
public final Point2D getPoint2D(Point2D src, Point2D dst)
{
- if (dst == null) return (Point2D)src.clone();
+ if (dst == null)
+ return (Point2D)src.clone();
+
dst.setLocation(src);
return dst;
}
@@ -159,7 +193,11 @@ public class BandCombineOp implements RasterOp
return hints;
}
- /** Return the matrix for this Op. */
+ /**
+ * Return the matrix used in this operation.
+ *
+ * @return The matrix used in this operation.
+ */
public final float[][] getMatrix()
{
return matrix;
diff --git a/java/awt/image/ColorConvertOp.java b/java/awt/image/ColorConvertOp.java
index 1f85a5ecd..e6c85412d 100644
--- a/java/awt/image/ColorConvertOp.java
+++ b/java/awt/image/ColorConvertOp.java
@@ -38,7 +38,10 @@ exception statement from your version. */
package java.awt.image;
+import gnu.java.awt.Buffers;
+
import java.awt.Graphics2D;
+import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
@@ -47,9 +50,9 @@ import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
- * ColorConvertOp is a filter for converting an image from one colorspace to
- * another colorspace. The filter can convert the image through a sequence
- * of colorspaces or just from source to destination.
+ * ColorConvertOp is a filter for converting images or rasters between
+ * colorspaces, either through a sequence of colorspaces or just from source to
+ * destination.
*
* Color conversion is done on the color components without alpha. Thus
* if a BufferedImage has alpha premultiplied, this is divided out before
@@ -63,24 +66,22 @@ import java.awt.geom.Rectangle2D;
*/
public class ColorConvertOp implements BufferedImageOp, RasterOp
{
- private ColorSpace srccs;
- private ColorSpace dstcs;
private RenderingHints hints;
- private ICC_Profile[] profiles;
+ private ICC_Profile[] profiles = null;
private ColorSpace[] spaces;
- private boolean rasterValid;
/**
- * Convert BufferedImage through a ColorSpace.
+ * Convert a BufferedImage through a ColorSpace.
*
- * This filter version is only valid for BufferedImages. The source image
- * is converted to cspace. If the destination is not null, it is then
- * converted to the destination colorspace. Normally this filter will only
- * be used with a null destination.
+ * Objects created with this constructor can be used to convert
+ * BufferedImage's to a destination ColorSpace. Attempts to convert Rasters
+ * with this constructor will result in an IllegalArgumentException when the
+ * filter(Raster, WritableRaster) method is called.
*
* @param cspace The target color space.
- * @param hints Rendering hints to use in conversion, or null.
+ * @param hints Rendering hints to use in conversion, if any (may be null)
+ * @throws NullPointerException if the ColorSpace is null.
*/
public ColorConvertOp(ColorSpace cspace, RenderingHints hints)
{
@@ -88,9 +89,27 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp
throw new NullPointerException();
spaces = new ColorSpace[]{cspace};
this.hints = hints;
- rasterValid = false;
}
+ /**
+ * Convert from a source colorspace to a destination colorspace.
+ *
+ * This constructor takes two ColorSpace arguments as the source and
+ * destination color spaces. It is usually used with the
+ * filter(Raster, WritableRaster) method, in which case the source colorspace
+ * is assumed to correspond to the source Raster, and the destination
+ * colorspace with the destination Raster.
+ *
+ * If used with BufferedImages that do not match the source or destination
+ * colorspaces specified here, there is an implicit conversion from the
+ * source image to the source ColorSpace, or the destination ColorSpace to
+ * the destination image.
+ *
+ * @param srcCspace The source ColorSpace.
+ * @param dstCspace The destination ColorSpace.
+ * @param hints Rendering hints to use in conversion, if any (may be null).
+ * @throws NullPointerException if any ColorSpace is null.
+ */
public ColorConvertOp(ColorSpace srcCspace, ColorSpace dstCspace,
RenderingHints hints)
{
@@ -101,61 +120,77 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp
}
/**
- * Convert from a source image destination image color space.
+ * Convert from a source colorspace to a destinatino colorspace.
*
* This constructor builds a ColorConvertOp from an array of ICC_Profiles.
- * The source image will be converted through the sequence of color spaces
+ * The source will be converted through the sequence of color spaces
* defined by the profiles. If the sequence of profiles doesn't give a
- * well-defined conversion, throws IllegalArgumentException.
- *
- * NOTE: Sun's docs don't clearly define what a well-defined conversion is
- * - or perhaps someone smarter can come along and sort it out.
+ * well-defined conversion, an IllegalArgumentException is thrown.
*
- * For BufferedImages, when the first and last profiles match the
- * requirements of the source and destination color space respectively, the
- * corresponding conversion is unnecessary. TODO: code this up. I don't
- * yet understand how you determine this.
+ * If used with BufferedImages that do not match the source or destination
+ * colorspaces specified here, there is an implicit conversion from the
+ * source image to the source ColorSpace, or the destination ColorSpace to
+ * the destination image.
*
* For Rasters, the first and last profiles must have the same number of
* bands as the source and destination Rasters, respectively. If this is
* not the case, or there fewer than 2 profiles, an IllegalArgumentException
* will be thrown.
*
- * @param profiles
- * @param hints
+ * @param profiles An array of ICC_Profile's to convert through.
+ * @param hints Rendering hints to use in conversion, if any (may be null).
+ * @throws NullPointerException if the profile array is null.
+ * @throws IllegalArgumentException if the array is not a well-defined
+ * conversion.
*/
public ColorConvertOp(ICC_Profile[] profiles, RenderingHints hints)
{
if (profiles == null)
throw new NullPointerException();
+
this.hints = hints;
this.profiles = profiles;
- // TODO: Determine if this is well-defined.
+
// Create colorspace array with space for src and dest colorspace
+ // Note that the ICC_ColorSpace constructor will throw an
+ // IllegalArgumentException if the profile is invalid; thus we check
+ // for a "well defined conversion"
spaces = new ColorSpace[profiles.length];
for (int i = 0; i < profiles.length; i++)
spaces[i] = new ICC_ColorSpace(profiles[i]);
}
- /** Convert from source image color space to destination image color space.
+ /**
+ * Convert from source color space to destination color space.
*
* Only valid for BufferedImage objects, this Op converts from the source
- * color space to the destination color space. The destination can't be
- * null for this operation.
+ * image's color space to the destination image's color space.
*
- * @param hints Rendering hints to use during conversion, or null.
+ * The destination in the filter(BufferedImage, BufferedImage) method cannot
+ * be null for this operation, and it also cannot be used with the
+ * filter(Raster, WritableRaster) method.
+ *
+ * @param hints Rendering hints to use in conversion, if any (may be null).
*/
public ColorConvertOp(RenderingHints hints)
{
- this.hints = hints;
- srccs = null;
- dstcs = null;
- rasterValid = false;
+ this.hints = hints;
+ spaces = new ColorSpace[0];
}
- /* (non-Javadoc)
- * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage,
- java.awt.image.BufferedImage)
+ /**
+ * Converts the source image using the conversion path specified in the
+ * constructor. The resulting image is stored in the destination image if one
+ * is provided; otherwise a new BufferedImage is created and returned.
+ *
+ * The source and destination BufferedImage (if one is supplied) must have
+ * the same dimensions.
+ *
+ * @param src The source image.
+ * @param dst The destination image.
+ * @throws IllegalArgumentException if the rasters and/or color spaces are
+ * incompatible.
+ * @return The transformed image.
*/
public final BufferedImage filter(BufferedImage src, BufferedImage dst)
{
@@ -163,129 +198,241 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp
// For now we just suck it up and create intermediate buffers.
if (dst == null && spaces.length == 0)
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException("Not enough color space information "
+ + "to complete conversion.");
+
+ if (dst != null
+ && (src.getHeight() != dst.getHeight() || src.getWidth() != dst.getWidth()))
+ throw new IllegalArgumentException("Source and destination images have "
+ + "different dimensions");
// Make sure input isn't premultiplied by alpha
if (src.isAlphaPremultiplied())
- {
- BufferedImage tmp = createCompatibleDestImage(src, src.getColorModel());
- copyimage(src, tmp);
- tmp.coerceData(false);
- src = tmp;
- }
+ {
+ BufferedImage tmp = createCompatibleDestImage(src, src.getColorModel());
+ copyimage(src, tmp);
+ tmp.coerceData(false);
+ src = tmp;
+ }
- ColorModel scm = src.getColorModel();
+ // Convert through defined intermediate conversions
+ BufferedImage tmp;
for (int i = 0; i < spaces.length; i++)
- {
- BufferedImage tmp = createCompatibleDestImage(src, scm);
- copyimage(src, tmp);
- src = tmp;
- }
+ {
+ if (src.getColorModel().getColorSpace().getType() != spaces[i].getType())
+ {
+ tmp = createCompatibleDestImage(src,
+ createCompatibleColorModel(src,
+ spaces[i]));
+ copyimage(src, tmp);
+ src = tmp;
+ }
+ }
- // Intermediate conversions leave result in src
+ // No implicit conversion to destination type needed; return result from the
+ // last intermediate conversions (which was left in src)
if (dst == null)
- return src;
-
- // Apply final conversion
- copyimage(src, dst);
-
+ dst = src;
+
+ // Implicit conversion to destination image's color space
+ else
+ copyimage(src, dst);
+
return dst;
}
- /* (non-Javadoc)
- * @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, java.awt.image.ColorModel)
+ /**
+ * Converts the source raster using the conversion path specified in the
+ * constructor. The resulting raster is stored in the destination raster if
+ * one is provided; otherwise a new WritableRaster is created and returned.
+ *
+ * This operation is not valid with every constructor of this class; see
+ * the constructors for details. Further, the source raster must have the
+ * same number of bands as the source ColorSpace, and the destination raster
+ * must have the same number of bands as the destination ColorSpace.
+ *
+ * The source and destination raster (if one is supplied) must also have the
+ * same dimensions.
+ *
+ * @param src The source raster.
+ * @param dest The destination raster.
+ * @throws IllegalArgumentException if the rasters and/or color spaces are
+ * incompatible.
+ * @return The transformed raster.
+ */
+ public final WritableRaster filter(Raster src, WritableRaster dest)
+ {
+ // Various checks to ensure that the rasters and color spaces are compatible
+ if (spaces.length < 2)
+ throw new IllegalArgumentException("Not enough information about " +
+ "source and destination colorspaces.");
+
+ if (spaces[0].getNumComponents() != src.getNumBands()
+ || (dest != null && spaces[spaces.length - 1].getNumComponents() != dest.getNumBands()))
+ throw new IllegalArgumentException("Source or destination raster " +
+ "contains the wrong number of bands.");
+
+ if (dest != null
+ && (src.getHeight() != dest.getHeight() || src.getWidth() != dest.getWidth()))
+ throw new IllegalArgumentException("Source and destination rasters " +
+ "have different dimensions");
+
+ // Need to iterate through each color space.
+ // spaces[0] corresponds to the ColorSpace of the source raster, and
+ // spaces[spaces.length - 1] corresponds to the ColorSpace of the
+ // destination, with any number (or zero) of intermediate conversions.
+
+ for (int i = 0; i < spaces.length - 2; i++)
+ {
+ WritableRaster tmp = createCompatibleDestRaster(src, spaces[i + 1],
+ false,
+ src.getTransferType());
+ copyraster(src, spaces[i], tmp, spaces[i + 1]);
+ src = tmp;
+ }
+
+ // The last conversion is done outside of the loop so that we can
+ // use the dest raster supplied, instead of creating our own temp raster
+ if (dest == null)
+ dest = createCompatibleDestRaster(src, spaces[spaces.length - 1], false,
+ DataBuffer.TYPE_BYTE);
+ copyraster(src, spaces[spaces.length - 2], dest, spaces[spaces.length - 1]);
+
+ return dest;
+ }
+
+ /**
+ * Creates an empty BufferedImage with the size equal to the source and the
+ * correct number of bands for the conversion defined in this Op. The newly
+ * created image is created with the specified ColorModel, or if no ColorModel
+ * is supplied, an appropriate one is chosen.
+ *
+ * @param src The source image.
+ * @param dstCM A color model for the destination image (may be null).
+ * @throws IllegalArgumentException if an appropriate colormodel cannot be
+ * chosen with the information given.
+ * @return The new compatible destination image.
*/
public BufferedImage createCompatibleDestImage(BufferedImage src,
- ColorModel dstCM)
+ ColorModel dstCM)
{
- // FIXME: set properties to those in src
+ if (dstCM == null && spaces.length == 0)
+ throw new IllegalArgumentException("Don't know the destination " +
+ "colormodel");
+
+ if (dstCM == null)
+ {
+ dstCM = createCompatibleColorModel(src, spaces[spaces.length - 1]);
+ }
+
return new BufferedImage(dstCM,
- src.getRaster().createCompatibleWritableRaster(),
- src.isPremultiplied,
- null);
+ createCompatibleDestRaster(src.getRaster(),
+ dstCM.getColorSpace(),
+ src.getColorModel().hasAlpha,
+ dstCM.getTransferType()),
+ src.isPremultiplied, null);
}
- public final ICC_Profile[] getICC_Profiles()
+ /**
+ * Creates a new WritableRaster with the size equal to the source and the
+ * correct number of bands.
+ *
+ * Note, the new Raster will always use a BYTE storage size, regardless of
+ * the color model or defined destination; this is for compatibility with
+ * the reference implementation.
+ *
+ * @param src The source Raster.
+ * @throws IllegalArgumentException if there isn't enough colorspace
+ * information to create a compatible Raster.
+ * @return The new compatible destination raster.
+ */
+ public WritableRaster createCompatibleDestRaster(Raster src)
{
- return profiles;
- }
+ if (spaces.length < 2)
+ throw new IllegalArgumentException("Not enough destination colorspace " +
+ "information");
- /** Return the rendering hints for this op. */
- public final RenderingHints getRenderingHints()
- {
- return hints;
+ // Create a new raster with the last ColorSpace in the conversion
+ // chain, and with no alpha (implied)
+ return createCompatibleDestRaster(src, spaces[spaces.length-1], false,
+ DataBuffer.TYPE_BYTE);
}
- /* (non-Javadoc)
- * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, java.awt.image.WritableRaster)
+ /**
+ * Returns the array of ICC_Profiles used to create this Op, or null if the
+ * Op was created using ColorSpace arguments.
+ *
+ * @return The array of ICC_Profiles, or null.
*/
- public final WritableRaster filter(Raster src, WritableRaster dest)
+ public final ICC_Profile[] getICC_Profiles()
{
- if (!rasterValid)
- throw new IllegalArgumentException();
-
- // Need to iterate through each color space - there must be at least 2
- for (int i = 1; i < spaces.length - 1; i++)
- {
- // FIXME: this is wrong. tmp needs to have the same number of bands as
- // spaces[i] has.
- WritableRaster tmp = createCompatibleDestRaster(src);
- copyraster(src, spaces[i - 1], tmp, spaces[i]);
- src = tmp;
- }
-
- // FIXME: this is wrong. dst needs to have the same number of bands as
- // spaces[i] has.
- if (dest == null)
- dest = createCompatibleDestRaster(src);
- copyraster(src, spaces[spaces.length - 2],
- dest, spaces[spaces.length - 1]);
-
- return dest;
+ return profiles;
}
- /* (non-Javadoc)
- * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster)
+ /**
+ * Returns the rendering hints for this op.
+ *
+ * @return The rendering hints for this Op, or null.
*/
- public WritableRaster createCompatibleDestRaster(Raster src)
+ public final RenderingHints getRenderingHints()
{
- return src.createCompatibleWritableRaster();
+ return hints;
}
- /** Return corresponding destination point for source point.
+ /**
+ * Returns the corresponding destination point for a source point.
+ * Because this is not a geometric operation, the destination and source
+ * points will be identical.
*
- * LookupOp will return the value of src unchanged.
* @param src The source point.
- * @param dst The destination point.
- * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D)
+ * @param dst The transformed destination point.
+ * @return The transformed destination point.
*/
public final Point2D getPoint2D(Point2D src, Point2D dst)
{
- if (dst == null) return (Point2D)src.clone();
+ if (dst == null)
+ return (Point2D)src.clone();
+
dst.setLocation(src);
return dst;
}
- /* (non-Javadoc)
- * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage)
+ /**
+ * Returns the corresponding destination boundary of a source boundary.
+ * Because this is not a geometric operation, the destination and source
+ * boundaries will be identical.
+ *
+ * @param src The source boundary.
+ * @return The boundaries of the destination.
*/
public final Rectangle2D getBounds2D(BufferedImage src)
{
return src.getRaster().getBounds();
}
- /* (non-Javadoc)
- * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster)
+ /**
+ * Returns the corresponding destination boundary of a source boundary.
+ * Because this is not a geometric operation, the destination and source
+ * boundaries will be identical.
+ *
+ * @param src The source boundary.
+ * @return The boundaries of the destination.
*/
public final Rectangle2D getBounds2D(Raster src)
{
return src.getBounds();
}
-
- // According to Sven de Marothy, we need to copy the src into the dest
- // using Graphics2D, in order to use the rendering hints.
+
+ /**
+ * Copy a source image to a destination image, respecting their colorspaces
+ * and performing colorspace conversions if necessary.
+ *
+ * @param src The source image.
+ * @param dst The destination image.
+ */
private void copyimage(BufferedImage src, BufferedImage dst)
{
+ // This is done using Graphics2D in order to respect the rendering hints.
Graphics2D gg = dst.createGraphics();
// If no hints are set there is no need to call
@@ -297,13 +444,23 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp
gg.dispose();
}
- private void copyraster(Raster src, ColorSpace scs, WritableRaster dst,
- ColorSpace dcs)
+ /**
+ * Copy a source raster to a destination raster, performing a colorspace
+ * conversion between the two. The conversion will respect the
+ * KEY_COLOR_RENDERING rendering hint if one is present.
+ *
+ * @param src The source raster.
+ * @param scs The colorspace of the source raster.
+ * @dst The destination raster.
+ * @dcs The colorspace of the destination raster.
+ */
+ private void copyraster(Raster src, ColorSpace scs, WritableRaster dst, ColorSpace dcs)
{
float[] sbuf = new float[src.getNumBands()];
- if (hints.get(RenderingHints.KEY_COLOR_RENDERING) ==
- RenderingHints.VALUE_COLOR_RENDER_QUALITY)
+ if (hints != null
+ && hints.get(RenderingHints.KEY_COLOR_RENDERING) ==
+ RenderingHints.VALUE_COLOR_RENDER_QUALITY)
{
// use cie for accuracy
for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++)
@@ -321,4 +478,60 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp
}
}
+ /**
+ * This method creates a color model with the same colorspace and alpha
+ * settings as the source image. The created color model will always be a
+ * ComponentColorModel and have a BYTE transfer type.
+ *
+ * @param img The source image.
+ * @param cs The ColorSpace to use.
+ * @return A color model compatible with the source image.
+ */
+ private ColorModel createCompatibleColorModel(BufferedImage img, ColorSpace cs)
+ {
+ // The choice of ComponentColorModel and DataBuffer.TYPE_BYTE is based on
+ // Mauve testing of the reference implementation.
+ return new ComponentColorModel(cs,
+ img.getColorModel().hasAlpha(),
+ img.isAlphaPremultiplied(),
+ img.getColorModel().getTransparency(),
+ DataBuffer.TYPE_BYTE);
+ }
+
+ /**
+ * This method creates a compatible Raster, given a source raster, colorspace,
+ * alpha value, and transfer type.
+ *
+ * @param src The source raster.
+ * @param cs The ColorSpace to use.
+ * @param hasAlpha Whether the raster should include a component for an alpha.
+ * @param transferType The size of a single data element.
+ * @return A compatible WritableRaster.
+ */
+ private WritableRaster createCompatibleDestRaster(Raster src, ColorSpace cs,
+ boolean hasAlpha,
+ int transferType)
+ {
+ // The use of a PixelInterleavedSampleModel weas determined using mauve
+ // tests, based on the reference implementation
+
+ int numComponents = cs.getNumComponents();
+ if (hasAlpha)
+ numComponents++;
+
+ int[] offsets = new int[numComponents];
+ for (int i = 0; i < offsets.length; i++)
+ offsets[i] = i;
+
+ DataBuffer db = Buffers.createBuffer(transferType,
+ src.getWidth() * src.getHeight() * numComponents,
+ 1);
+ return new WritableRaster(new PixelInterleavedSampleModel(transferType,
+ src.getWidth(),
+ src.getHeight(),
+ numComponents,
+ numComponents * src.getWidth(),
+ offsets),
+ db, new Point(src.getMinX(), src.getMinY()));
+ }
}
diff --git a/java/awt/image/ColorModel.java b/java/awt/image/ColorModel.java
index 9e559db37..fc413d0b4 100644
--- a/java/awt/image/ColorModel.java
+++ b/java/awt/image/ColorModel.java
@@ -628,7 +628,7 @@ public abstract class ColorModel implements Transparency
public ColorModel coerceData(WritableRaster raster,
boolean isAlphaPremultiplied)
{
- if (this.isAlphaPremultiplied == isAlphaPremultiplied)
+ if (this.isAlphaPremultiplied == isAlphaPremultiplied || ! hasAlpha)
return this;
int w = raster.getWidth();
diff --git a/java/awt/image/ComponentColorModel.java b/java/awt/image/ComponentColorModel.java
index f56688f93..f3f3e374b 100644
--- a/java/awt/image/ComponentColorModel.java
+++ b/java/awt/image/ComponentColorModel.java
@@ -42,9 +42,11 @@ import gnu.java.awt.Buffers;
import java.awt.Point;
import java.awt.color.ColorSpace;
+import java.util.Arrays;
public class ComponentColorModel extends ColorModel
{
+ // Find sum of all elements of the array.
private static int sum(int[] values)
{
int sum = 0;
@@ -52,6 +54,22 @@ public class ComponentColorModel extends ColorModel
sum += values[i];
return sum;
}
+
+ // Create an appropriate array of bits, given a colorspace (ie, number of
+ // bands), size of the storage data type, and presence of an alpha band.
+ private static int[] findBits(ColorSpace colorSpace, int transferType,
+ boolean hasAlpha)
+ {
+ int[] bits;
+ if (hasAlpha)
+ bits = new int[colorSpace.getNumComponents()+1];
+ else
+ bits = new int[colorSpace.getNumComponents()];
+
+ Arrays.fill(bits, DataBuffer.getDataTypeSize(transferType));
+
+ return bits;
+ }
public ComponentColorModel(ColorSpace colorSpace, int[] bits,
boolean hasAlpha,
@@ -84,8 +102,8 @@ public class ComponentColorModel extends ColorModel
boolean isAlphaPremultiplied,
int transparency, int transferType)
{
- this(colorSpace, null, hasAlpha, isAlphaPremultiplied,
- transparency, transferType);
+ this(colorSpace, findBits(colorSpace, transferType, hasAlpha), hasAlpha,
+ isAlphaPremultiplied, transparency, transferType);
}
public int getRed(int pixel)
diff --git a/java/awt/image/ConvolveOp.java b/java/awt/image/ConvolveOp.java
index ffb834874..cd3b01131 100644
--- a/java/awt/image/ConvolveOp.java
+++ b/java/awt/image/ConvolveOp.java
@@ -38,7 +38,6 @@ exception statement from your version. */
package java.awt.image;
-import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
@@ -51,11 +50,13 @@ import java.awt.geom.Rectangle2D;
* with elements in the kernel to compute a new pixel.
*
* Each band in a Raster is convolved and copied to the destination Raster.
+ * For BufferedImages, convolution is applied to all components. Color
+ * conversion will be applied if needed.
*
- * For BufferedImages, convolution is applied to all components. If the
- * source is not premultiplied, the data will be premultiplied before
- * convolving. Premultiplication will be undone if the destination is not
- * premultiplied. Color conversion will be applied if needed.
+ * Note that this filter ignores whether the source or destination is alpha
+ * premultiplied. The reference spec states that data will be premultiplied
+ * prior to convolving and divided back out afterwards (if needed), but testing
+ * has shown that this is not the case with their implementation.
*
* @author jlquinn@optonline.net
*/
@@ -104,59 +105,83 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
hints = null;
}
-
- /* (non-Javadoc)
- * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage,
- * java.awt.image.BufferedImage)
+ /**
+ * Converts the source image using the kernel specified in the
+ * constructor. The resulting image is stored in the destination image if one
+ * is provided; otherwise a new BufferedImage is created and returned.
+ *
+ * The source and destination BufferedImage (if one is supplied) must have
+ * the same dimensions.
+ *
+ * @param src The source image.
+ * @param dst The destination image.
+ * @throws IllegalArgumentException if the rasters and/or color spaces are
+ * incompatible.
+ * @return The convolved image.
*/
public final BufferedImage filter(BufferedImage src, BufferedImage dst)
{
if (src == dst)
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException("Source and destination images " +
+ "cannot be the same.");
if (dst == null)
dst = createCompatibleDestImage(src, src.getColorModel());
// Make sure source image is premultiplied
BufferedImage src1 = src;
- if (!src.isPremultiplied)
+ // The spec says we should do this, but mauve testing shows that Sun's
+ // implementation does not check this.
+ /*
+ if (!src.isAlphaPremultiplied())
{
src1 = createCompatibleDestImage(src, src.getColorModel());
src.copyData(src1.getRaster());
src1.coerceData(true);
}
+ */
BufferedImage dst1 = dst;
- if (!src.getColorModel().equals(dst.getColorModel()))
+ if (src1.getColorModel().getColorSpace().getType() != dst.getColorModel().getColorSpace().getType())
dst1 = createCompatibleDestImage(src, src.getColorModel());
filter(src1.getRaster(), dst1.getRaster());
+ // Since we don't coerceData above, we don't need to divide it back out.
+ // This is wrong (one mauve test specifically tests converting a non-
+ // premultiplied image to a premultiplied image, and it shows that Sun
+ // simply ignores the premultipled flag, contrary to the spec), but we
+ // mimic it for compatibility.
+ /*
+ if (! dst.isAlphaPremultiplied())
+ dst1.coerceData(false);
+ */
+
+ // Convert between color models if needed
if (dst1 != dst)
- {
- // Convert between color models.
- // TODO Check that premultiplied alpha is handled correctly here.
- Graphics2D gg = dst.createGraphics();
- gg.setRenderingHints(hints);
- gg.drawImage(dst1, 0, 0, null);
- gg.dispose();
- }
-
+ new ColorConvertOp(hints).filter(dst1, dst);
+
return dst;
}
- /* (non-Javadoc)
- * @see
- * java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage,
- * java.awt.image.ColorModel)
+ /**
+ * Creates an empty BufferedImage with the size equal to the source and the
+ * correct number of bands. The new image is created with the specified
+ * ColorModel, or if no ColorModel is supplied, an appropriate one is chosen.
+ *
+ * @param src The source image.
+ * @param dstCM A color model for the destination image (may be null).
+ * @return The new compatible destination image.
*/
public BufferedImage createCompatibleDestImage(BufferedImage src,
- ColorModel dstCM)
+ ColorModel dstCM)
{
- // FIXME: set properties to those in src
- return new BufferedImage(dstCM,
- src.getRaster().createCompatibleWritableRaster(),
- src.isPremultiplied, null);
+ if (dstCM != null)
+ return new BufferedImage(dstCM,
+ src.getRaster().createCompatibleWritableRaster(),
+ src.isAlphaPremultiplied(), null);
+
+ return new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
}
/* (non-Javadoc)
@@ -168,6 +193,8 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
}
/**
+ * Get the edge condition for this Op.
+ *
* @return The edge condition.
*/
public int getEdgeCondition()
@@ -185,9 +212,22 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
return (Kernel) kernel.clone();
}
- /* (non-Javadoc)
- * @see java.awt.image.RasterOp#filter(java.awt.image.Raster,
- * java.awt.image.WritableRaster)
+ /**
+ * Converts the source raster using the kernel specified in the constructor.
+ * The resulting raster is stored in the destination raster if one is
+ * provided; otherwise a new WritableRaster is created and returned.
+ *
+ * If the convolved value for a sample is outside the range of [0-255], it
+ * will be clipped.
+ *
+ * The source and destination raster (if one is supplied) cannot be the same,
+ * and must also have the same dimensions.
+ *
+ * @param src The source raster.
+ * @param dest The destination raster.
+ * @throws IllegalArgumentException if the rasters identical.
+ * @throws ImagingOpException if the convolution is not possible.
+ * @return The transformed raster.
*/
public final WritableRaster filter(Raster src, WritableRaster dest)
{
@@ -228,7 +268,16 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
v += tmp[tmp.length - i - 1] * kvals[i];
// FIXME: in the above line, I've had to reverse the order of
// the samples array to make the tests pass. I haven't worked
- // out why this is necessary.
+ // out why this is necessary.
+
+ // This clipping is pretty strange, and seems to be hard-coded
+ // at 255 (regardless of the raster's datatype or transfertype).
+ // But it's what the reference does.
+ if (v > 255)
+ v = 255;
+ if (v < 0)
+ v = 0;
+
dest.setSample(x + kernel.getXOrigin(), y + kernel.getYOrigin(),
b, v);
}
@@ -310,13 +359,14 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
return src.getBounds();
}
- /** Return corresponding destination point for source point.
+ /**
+ * Returns the corresponding destination point for a source point. Because
+ * this is not a geometric operation, the destination and source points will
+ * be identical.
*
- * ConvolveOp will return the value of src unchanged.
* @param src The source point.
- * @param dst The destination point.
- * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D,
- * java.awt.geom.Point2D)
+ * @param dst The transformed destination point.
+ * @return The transformed destination point.
*/
public final Point2D getPoint2D(Point2D src, Point2D dst)
{
diff --git a/java/io/File.java b/java/io/File.java
index 7dbc6109e..4f5ab4e66 100644
--- a/java/io/File.java
+++ b/java/io/File.java
@@ -286,7 +286,8 @@ public class File implements Serializable, Comparable<File>
// example, is a valid and minimal path).
if (plen > 1 && p.charAt (plen - 1) == separatorChar)
{
- if (! (separatorChar == '\\' && plen == 3 && p.charAt (1) == ':'))
+ if (! (separatorChar == '\\' && ((plen == 3 && p.charAt(1) == ':')
+ || (plen == 2 && p.charAt(0) == separatorChar))))
return p.substring (0, plen - 1);
}
else
@@ -303,7 +304,16 @@ public class File implements Serializable, Comparable<File>
{
dupIndex++;
if (dupIndex == plen)
- return newpath.toString();
+ {
+ if ((separatorChar == '\\'
+ && newpath.length() == 2
+ && newpath.charAt(1) == ':')
+ || (separatorChar != '\\' && newpath.length() == 0))
+ {
+ newpath.append(separatorChar);
+ }
+ return newpath.toString();
+ }
}
newpath.append(separatorChar);
last = dupIndex;
@@ -315,7 +325,9 @@ public class File implements Serializable, Comparable<File>
int end;
if (plen > 1 && p.charAt (plen - 1) == separatorChar)
{
- if (separatorChar == '\\' && plen == 3 && p.charAt (1) == ':')
+ if (separatorChar == '\\'
+ && ((plen == 3 && p.charAt(1) == ':')
+ || (plen == 2 && p.charAt(0) == separatorChar)))
end = plen;
else
end = plen - 1;
@@ -427,45 +439,8 @@ public class File implements Serializable, Comparable<File>
{
if (isAbsolute())
return path;
- else if (separatorChar == '\\'
- && path.length() > 0 && path.charAt (0) == '\\')
- {
- // On Windows, even if the path starts with a '\\' it is not
- // really absolute until we prefix the drive specifier from
- // the current working directory to it.
- return System.getProperty ("user.dir").substring (0, 2) + path;
- }
- else if (separatorChar == '\\'
- && path.length() > 1 && path.charAt (1) == ':'
- && ((path.charAt (0) >= 'a' && path.charAt (0) <= 'z')
- || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z')))
- {
- // On Windows, a process has a current working directory for
- // each drive and a path like "G:foo\bar" would mean the
- // absolute path "G:\wombat\foo\bar" if "\wombat" is the
- // working directory on the G drive.
- String drvDir = null;
- try
- {
- drvDir = new File (path.substring (0, 2)).getCanonicalPath();
- }
- catch (IOException e)
- {
- drvDir = path.substring (0, 2) + "\\";
- }
-
- // Note: this would return "C:\\." for the path "C:.", if "\"
- // is the working folder on the C drive, but this is
- // consistent with what Sun's JRE 1.4.1.01 actually returns!
- if (path.length() > 2)
- return drvDir + '\\' + path.substring (2, path.length());
- else
- return drvDir;
- }
- else if (path.equals(""))
- return System.getProperty ("user.dir");
else
- return System.getProperty ("user.dir") + separatorChar + path;
+ return VMFile.getAbsolutePath(path);
}
/**
@@ -657,15 +632,7 @@ public class File implements Serializable, Comparable<File>
*/
public boolean isAbsolute()
{
- if (separatorChar == '\\')
- return path.startsWith(dupSeparator) ||
- (path.length() > 2 &&
- ((path.charAt(0) >= 'a' && path.charAt(0) <= 'z') ||
- (path.charAt(0) >= 'A' && path.charAt(0) <= 'Z')) &&
- path.charAt(1) == ':' &&
- path.charAt(2) == '\\');
- else
- return path.startsWith(separator);
+ return VMFile.isAbsolute(path);
}
/**
@@ -998,14 +965,7 @@ public class File implements Serializable, Comparable<File>
*/
public URL toURL() throws MalformedURLException
{
- // On Win32, Sun's JDK returns URLs of the form "file:/c:/foo/bar.txt",
- // while on UNIX, it returns URLs of the form "file:/foo/bar.txt".
- if (separatorChar == '\\')
- return new URL ("file:/" + getAbsolutePath().replace ('\\', '/')
- + (isDirectory() ? "/" : ""));
- else
- return new URL ("file:" + getAbsolutePath()
- + (isDirectory() ? "/" : ""));
+ return VMFile.toURL(this);
}
diff --git a/java/io/FileDescriptor.java b/java/io/FileDescriptor.java
index d300c9cb6..dd3db1c74 100644
--- a/java/io/FileDescriptor.java
+++ b/java/io/FileDescriptor.java
@@ -133,7 +133,8 @@ public final class FileDescriptor
* native file handle, <code>false</code> otherwise
*/
public boolean valid ()
- {
- return channel != null && channel.isOpen();
+ {
+ ByteChannel c = channel;
+ return (c != null) && (c.isOpen());
}
}
diff --git a/java/io/InputStreamReader.java b/java/io/InputStreamReader.java
index 936a03c95..8d97799d5 100644
--- a/java/io/InputStreamReader.java
+++ b/java/io/InputStreamReader.java
@@ -135,6 +135,16 @@ public class InputStreamReader extends Reader
private boolean hasSavedSurrogate = false;
/**
+ * A byte array to be reused in read(byte[], int, int).
+ */
+ private byte[] bytesCache;
+
+ /**
+ * Locks the bytesCache above in read(byte[], int, int).
+ */
+ private Object cacheLock = new Object();
+
+ /**
* This method initializes a new instance of <code>InputStreamReader</code>
* to read from the specified stream using the default encoding.
*
@@ -355,9 +365,19 @@ public class InputStreamReader extends Reader
throw new IOException("Reader has been closed");
if (isDone)
return -1;
- if(decoder != null){
- int totalBytes = (int)((double)length * maxBytesPerChar);
- byte[] bytes = new byte[totalBytes];
+ if(decoder != null)
+ {
+ int totalBytes = (int)((double) length * maxBytesPerChar);
+ byte[] bytes;
+ // Fetch cached bytes array if available and big enough.
+ synchronized(cacheLock)
+ {
+ bytes = bytesCache;
+ if (bytes == null || bytes.length < totalBytes)
+ bytes = new byte[totalBytes];
+ else
+ bytesCache = null;
+ }
int remaining = 0;
if(byteBuffer != null)
@@ -410,12 +430,40 @@ public class InputStreamReader extends Reader
byteBuffer = null;
read = cb.position() - startPos;
- return (read <= 0) ? -1 : read;
- } else {
- byte[] bytes = new byte[length];
+
+ // Put cached bytes array back if we are finished and the cache
+ // is null or smaller than the used bytes array.
+ synchronized (cacheLock)
+ {
+ if (byteBuffer == null
+ && (bytesCache == null || bytesCache.length < bytes.length))
+ bytesCache = bytes;
+ }
+ return (read <= 0) ? -1 : read;
+ }
+ else
+ {
+ byte[] bytes;
+ // Fetch cached bytes array if available and big enough.
+ synchronized (cacheLock)
+ {
+ bytes = bytesCache;
+ if (bytes == null || length < bytes.length)
+ bytes = new byte[length];
+ else
+ bytesCache = null;
+ }
+
int read = in.read(bytes);
for(int i=0;i<read;i++)
buf[offset+i] = (char)(bytes[i]&0xFF);
+
+ // Put back byte array into cache if appropriate.
+ synchronized (cacheLock)
+ {
+ if (bytesCache == null || bytesCache.length < bytes.length)
+ bytesCache = bytes;
+ }
return read;
}
}
diff --git a/java/io/ObjectInputStream.java b/java/io/ObjectInputStream.java
index 98632607c..d6c1406ea 100644
--- a/java/io/ObjectInputStream.java
+++ b/java/io/ObjectInputStream.java
@@ -39,7 +39,7 @@ exception statement from your version. */
package java.io;
-import gnu.java.io.ObjectIdentityWrapper;
+import gnu.classpath.VMStackWalker;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
@@ -104,7 +104,7 @@ public class ObjectInputStream extends InputStream
this.blockDataInput = new DataInputStream(this);
this.realInputStream = new DataInputStream(in);
this.nextOID = baseWireHandle;
- this.objectLookupTable = new Hashtable<Integer,ObjectIdentityWrapper>();
+ this.objectLookupTable = new Vector<Object>();
this.classLookupTable = new Hashtable<Class,ObjectStreamClass>();
setBlockDataMode(true);
readStreamHeader();
@@ -204,10 +204,9 @@ public class ObjectInputStream extends InputStream
case TC_REFERENCE:
{
if(dump) dumpElement("REFERENCE ");
- Integer oid = new Integer(this.realInputStream.readInt());
- if(dump) dumpElementln(Integer.toHexString(oid.intValue()));
- ret_val = ((ObjectIdentityWrapper)
- this.objectLookupTable.get(oid)).object;
+ int oid = realInputStream.readInt();
+ if(dump) dumpElementln(Integer.toHexString(oid));
+ ret_val = lookupHandle(oid);
break;
}
@@ -360,8 +359,7 @@ public class ObjectInputStream extends InputStream
this.currentObject = obj;
this.currentObjectValidators = null;
- ObjectStreamClass[] hierarchy =
- inputGetObjectStreamClasses(clazz);
+ ObjectStreamClass[] hierarchy = hierarchy(clazz);
for (int i = 0; i < hierarchy.length; i++)
{
@@ -825,7 +823,7 @@ public class ObjectInputStream extends InputStream
*/
private ClassLoader currentLoader()
{
- return VMObjectInputStream.currentClassLoader();
+ return VMStackWalker.firstNonNullClassLoader();
}
/**
@@ -853,41 +851,20 @@ public class ObjectInputStream extends InputStream
}
/**
- * Reconstruct class hierarchy the same way
- * {@link java.io.ObjectStreamClass#getObjectStreamClasses(Class)} does
- * but using lookupClass instead of ObjectStreamClass.lookup. This
- * dup is necessary localize the lookup table. Hopefully some future
- * rewritings will be able to prevent this.
+ * Reconstruct class hierarchy the same way {@link
+ * java.io.ObjectStreamClass#hierarchy} does but using lookupClass
+ * instead of ObjectStreamClass.lookup.
*
* @param clazz This is the class for which we want the hierarchy.
*
* @return An array of valid {@link java.io.ObjectStreamClass} instances which
* represent the class hierarchy for clazz.
*/
- private ObjectStreamClass[] inputGetObjectStreamClasses(Class clazz)
- {
+ private ObjectStreamClass[] hierarchy(Class clazz)
+ {
ObjectStreamClass osc = lookupClass(clazz);
- if (osc == null)
- return new ObjectStreamClass[0];
- else
- {
- Vector<ObjectStreamClass> oscs = new Vector<ObjectStreamClass>();
-
- while (osc != null)
- {
- oscs.addElement(osc);
- osc = osc.getSuper();
- }
-
- int count = oscs.size();
- ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count];
-
- for (int i = count - 1; i >= 0; i--)
- sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i);
-
- return sorted_oscs;
- }
+ return osc == null ? new ObjectStreamClass[0] : osc.hierarchy();
}
/**
@@ -1571,9 +1548,47 @@ public class ObjectInputStream extends InputStream
*/
private int assignNewHandle(Object obj)
{
- this.objectLookupTable.put(new Integer(this.nextOID),
- new ObjectIdentityWrapper(obj));
- return this.nextOID++;
+ int handle = this.nextOID;
+ this.nextOID = handle + 1;
+ rememberHandle(obj,handle);
+ return handle;
+ }
+
+ /**
+ * Remember the object associated with the given handle.
+ *
+ * @param obj an object
+ *
+ * @param handle a handle, must be >= baseWireHandle
+ *
+ * @see #lookupHandle
+ */
+ private void rememberHandle(Object obj, int handle)
+ {
+ Vector olt = this.objectLookupTable;
+ handle = handle - baseWireHandle;
+
+ if (olt.size() <= handle)
+ olt.setSize(handle + 1);
+
+ olt.set(handle, obj);
+ }
+
+ /**
+ * Look up the object associated with a given handle.
+ *
+ * @param handle a handle, must be >= baseWireHandle
+ *
+ * @return the object remembered for handle or null if none.
+ *
+ * @see #rememberHandle
+ */
+ private Object lookupHandle(int handle)
+ {
+ Vector olt = this.objectLookupTable;
+ handle = handle - baseWireHandle;
+ Object result = handle < olt.size() ? olt.get(handle) : null;
+ return result;
}
private Object processResolution(ObjectStreamClass osc, Object obj, int handle)
@@ -1607,9 +1622,7 @@ public class ObjectInputStream extends InputStream
if (this.resolveEnabled)
obj = resolveObject(obj);
- this.objectLookupTable.put(new Integer(handle),
- new ObjectIdentityWrapper(obj));
-
+ rememberHandle(obj, handle);
return obj;
}
@@ -1942,7 +1955,7 @@ public class ObjectInputStream extends InputStream
private boolean useSubclassMethod;
private int nextOID;
private boolean resolveEnabled;
- private Hashtable<Integer,ObjectIdentityWrapper> objectLookupTable;
+ private Vector<Object> objectLookupTable;
private Object currentObject;
private ObjectStreamClass currentObjectStreamClass;
private TreeSet<ValidatorAndPriority> currentObjectValidators;
diff --git a/java/io/ObjectOutputStream.java b/java/io/ObjectOutputStream.java
index eb781acab..c3c3df9a3 100644
--- a/java/io/ObjectOutputStream.java
+++ b/java/io/ObjectOutputStream.java
@@ -39,7 +39,7 @@ exception statement from your version. */
package java.io;
-import gnu.java.io.ObjectIdentityWrapper;
+import gnu.java.io.ObjectIdentityMap2Int;
import gnu.java.lang.reflect.TypeSignature;
import gnu.java.security.action.SetAccessibleAction;
@@ -47,8 +47,6 @@ import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.security.AccessController;
-import java.util.Hashtable;
/**
@@ -146,7 +144,7 @@ public class ObjectOutputStream extends OutputStream
replacementEnabled = false;
isSerializing = false;
nextOID = baseWireHandle;
- OIDLookupTable = new Hashtable<ObjectIdentityWrapper,Integer>();
+ OIDLookupTable = new ObjectIdentityMap2Int();
protocolVersion = defaultProtocolVersion;
useSubclassMethod = false;
writeStreamHeader();
@@ -213,11 +211,11 @@ public class ObjectOutputStream extends OutputStream
break;
}
- Integer handle = findHandle(obj);
- if (handle != null)
+ int handle = findHandle(obj);
+ if (handle >= 0)
{
realOutput.writeByte(TC_REFERENCE);
- realOutput.writeInt(handle.intValue());
+ realOutput.writeInt(handle);
break;
}
@@ -231,7 +229,7 @@ public class ObjectOutputStream extends OutputStream
writeObject (osc);
}
else
- {
+ {System.err.println("1");
realOutput.writeByte(TC_PROXYCLASSDESC);
Class[] intfs = cl.getInterfaces();
realOutput.writeInt(intfs.length);
@@ -344,8 +342,7 @@ public class ObjectOutputStream extends OutputStream
Object prevObject = this.currentObject;
ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
currentObject = obj;
- ObjectStreamClass[] hierarchy =
- ObjectStreamClass.getObjectStreamClasses(clazz);
+ ObjectStreamClass[] hierarchy = osc.hierarchy();
for (int i = 0; i < hierarchy.length; i++)
{
@@ -1110,17 +1107,16 @@ public class ObjectOutputStream extends OutputStream
// lookup the handle for OBJ, return null if OBJ doesn't have a
// handle yet
- private Integer findHandle(Object obj)
+ private int findHandle(Object obj)
{
- return (Integer)OIDLookupTable.get(new ObjectIdentityWrapper(obj));
+ return OIDLookupTable.get(obj);
}
// assigns the next availible handle to OBJ
private int assignNewHandle(Object obj)
{
- OIDLookupTable.put(new ObjectIdentityWrapper(obj),
- new Integer(nextOID));
+ OIDLookupTable.put(obj, nextOID);
return nextOID++;
}
@@ -1222,39 +1218,70 @@ public class ObjectOutputStream extends OutputStream
{
ObjectStreamField[] fields = osc.fields;
boolean oldmode = setBlockDataMode(false);
- String field_name;
- Class type;
- for (int i = 0; i < fields.length; i++)
+ try
{
- field_name = fields[i].getName();
- type = fields[i].getType();
-
- if (dump)
- dumpElementln ("WRITE FIELD: " + field_name + " type=" + type);
-
- if (type == Boolean.TYPE)
- realOutput.writeBoolean(getBooleanField(obj, osc.forClass(), field_name));
- else if (type == Byte.TYPE)
- realOutput.writeByte(getByteField(obj, osc.forClass(), field_name));
- else if (type == Character.TYPE)
- realOutput.writeChar(getCharField(obj, osc.forClass(), field_name));
- else if (type == Double.TYPE)
- realOutput.writeDouble(getDoubleField(obj, osc.forClass(), field_name));
- else if (type == Float.TYPE)
- realOutput.writeFloat(getFloatField(obj, osc.forClass(), field_name));
- else if (type == Integer.TYPE)
- realOutput.writeInt(getIntField(obj, osc.forClass(), field_name));
- else if (type == Long.TYPE)
- realOutput.writeLong(getLongField(obj, osc.forClass(), field_name));
- else if (type == Short.TYPE)
- realOutput.writeShort(getShortField(obj, osc.forClass(), field_name));
- else
- writeObject(getObjectField(obj, osc.forClass(), field_name,
- fields[i].getTypeString ()));
+ writeFields(obj,fields);
+ }
+ catch (IllegalArgumentException _)
+ {
+ InvalidClassException e = new InvalidClassException
+ ("writing fields of class " + osc.forClass().getName());
+ e.initCause(_);
+ throw e;
+ }
+ catch (IOException e)
+ {
+ throw e;
}
+ catch (Exception _)
+ {
+ IOException e = new IOException("Unexpected exception " + _);
+ e.initCause(_);
+ throw(e);
+ }
+
setBlockDataMode(oldmode);
}
+
+
+ /**
+ * Helper function for writeFields(Object,ObjectStreamClass): write
+ * fields from given fields array. Pass exception on.
+ *
+ * @param obj the object to be written
+ *
+ * @param fields the fields of obj to be written.
+ */
+ private void writeFields(Object obj, ObjectStreamField[] fields)
+ throws
+ IllegalArgumentException, IllegalAccessException, IOException
+ {
+ for (int i = 0; i < fields.length; i++)
+ {
+ ObjectStreamField osf = fields[i];
+ Field field = osf.field;
+
+ if (DEBUG && dump)
+ dumpElementln ("WRITE FIELD: " + osf.getName() + " type=" + osf.getType());
+
+ switch (osf.getTypeCode())
+ {
+ case 'Z': realOutput.writeBoolean(field.getBoolean(obj)); break;
+ case 'B': realOutput.writeByte (field.getByte (obj)); break;
+ case 'S': realOutput.writeShort (field.getShort (obj)); break;
+ case 'C': realOutput.writeChar (field.getChar (obj)); break;
+ case 'I': realOutput.writeInt (field.getInt (obj)); break;
+ case 'F': realOutput.writeFloat (field.getFloat (obj)); break;
+ case 'J': realOutput.writeLong (field.getLong (obj)); break;
+ case 'D': realOutput.writeDouble (field.getDouble (obj)); break;
+ case 'L':
+ case '[': writeObject (field.get (obj)); break;
+ default:
+ throw new IOException("Unexpected type code " + osf.getTypeCode());
+ }
+ }
+ }
// Toggles writing primitive data to block-data buffer.
@@ -1313,248 +1340,6 @@ public class ObjectOutputStream extends OutputStream
}
}
- private boolean getBooleanField(Object obj, Class klass, String field_name)
- throws IOException
- {
- try
- {
- Field f = getField(klass, field_name);
- boolean b = f.getBoolean(obj);
- return b;
- }
- catch (IllegalArgumentException _)
- {
- throw new InvalidClassException
- ("invalid requested type for field " + field_name + " in class " + klass.getName());
- }
- catch (IOException e)
- {
- throw e;
- }
- catch (Exception _)
- {
- throw new IOException("Unexpected exception " + _);
- }
- }
-
- private byte getByteField (Object obj, Class klass, String field_name)
- throws IOException
- {
- try
- {
- Field f = getField (klass, field_name);
- byte b = f.getByte (obj);
- return b;
- }
- catch (IllegalArgumentException _)
- {
- throw new InvalidClassException
- ("invalid requested type for field " + field_name + " in class " + klass.getName());
- }
- catch (IOException e)
- {
- throw e;
- }
- catch (Exception _)
- {
- throw new IOException("Unexpected exception " + _);
- }
- }
-
- private char getCharField (Object obj, Class klass, String field_name)
- throws IOException
- {
- try
- {
- Field f = getField (klass, field_name);
- char b = f.getChar (obj);
- return b;
- }
- catch (IllegalArgumentException _)
- {
- throw new InvalidClassException
- ("invalid requested type for field " + field_name + " in class " + klass.getName());
- }
- catch (IOException e)
- {
- throw e;
- }
- catch (Exception _)
- {
- throw new IOException("Unexpected exception " + _);
- }
- }
-
- private double getDoubleField (Object obj, Class klass, String field_name)
- throws IOException
- {
- try
- {
- Field f = getField (klass, field_name);
- double b = f.getDouble (obj);
- return b;
- }
- catch (IllegalArgumentException _)
- {
- throw new InvalidClassException
- ("invalid requested type for field " + field_name + " in class " + klass.getName());
- }
- catch (IOException e)
- {
- throw e;
- }
- catch (Exception _)
- {
- throw new IOException("Unexpected exception " + _);
- }
- }
-
- private float getFloatField (Object obj, Class klass, String field_name)
- throws IOException
- {
- try
- {
- Field f = getField (klass, field_name);
- float b = f.getFloat (obj);
- return b;
- }
- catch (IllegalArgumentException _)
- {
- throw new InvalidClassException
- ("invalid requested type for field " + field_name + " in class " + klass.getName());
- }
- catch (IOException e)
- {
- throw e;
- }
- catch (Exception _)
- {
- throw new IOException("Unexpected exception " + _);
- }
- }
-
- private int getIntField (Object obj, Class klass, String field_name)
- throws IOException
- {
- try
- {
- Field f = getField (klass, field_name);
- int b = f.getInt (obj);
- return b;
- }
- catch (IllegalArgumentException _)
- {
- throw new InvalidClassException
- ("invalid requested type for field " + field_name + " in class " + klass.getName());
- }
- catch (IOException e)
- {
- throw e;
- }
- catch (Exception _)
- {
- throw new IOException("Unexpected exception " + _);
- }
- }
-
- private long getLongField (Object obj, Class klass, String field_name)
- throws IOException
- {
- try
- {
- Field f = getField (klass, field_name);
- long b = f.getLong (obj);
- return b;
- }
- catch (IllegalArgumentException _)
- {
- throw new InvalidClassException
- ("invalid requested type for field " + field_name + " in class " + klass.getName());
- }
- catch (IOException e)
- {
- throw e;
- }
- catch (Exception _)
- {
- throw new IOException("Unexpected exception " + _);
- }
- }
-
- private short getShortField (Object obj, Class klass, String field_name)
- throws IOException
- {
- try
- {
- Field f = getField (klass, field_name);
- short b = f.getShort (obj);
- return b;
- }
- catch (IllegalArgumentException _)
- {
- throw new InvalidClassException
- ("invalid requested type for field " + field_name + " in class " + klass.getName());
- }
- catch (IOException e)
- {
- throw e;
- }
- catch (Exception _)
- {
- throw new IOException("Unexpected exception " + _);
- }
- }
-
- private Object getObjectField (Object obj, Class klass, String field_name,
- String type_code) throws IOException
- {
- try
- {
- Field f = getField (klass, field_name);
- ObjectStreamField of = new ObjectStreamField(f.getName(), f.getType());
-
- /* if of is primitive something went wrong
- * in the check for primitive classes in writeFields.
- */
- if (of.isPrimitive())
- throw new InvalidClassException
- ("invalid type code for " + field_name + " in class " + klass.getName() + " : object stream field is primitive");
-
- if (!of.getTypeString().equals(type_code))
- throw new InvalidClassException
- ("invalid type code for " + field_name + " in class " + klass.getName() + " : object stream field " + of + " has type string " + of.getTypeString() + " instead of " + type_code);
-
- Object o = f.get (obj);
- // FIXME: We should check the type_code here
- return o;
- }
- catch (IOException e)
- {
- throw e;
- }
- catch (Exception e)
- {
- throw new IOException ();
- }
- }
-
- private Field getField (Class klass, String name)
- throws java.io.InvalidClassException
- {
- try
- {
- final Field f = klass.getDeclaredField(name);
- setAccessible.setMember(f);
- AccessController.doPrivileged(setAccessible);
- return f;
- }
- catch (java.lang.NoSuchFieldException e)
- {
- throw new InvalidClassException
- ("no field called " + name + " in class " + klass.getName());
- }
- }
-
private void dumpElementln (String msg)
{
for (int i = 0; i < depth; i++)
@@ -1582,7 +1367,7 @@ public class ObjectOutputStream extends OutputStream
private boolean replacementEnabled;
private boolean isSerializing;
private int nextOID;
- private Hashtable<ObjectIdentityWrapper,Integer> OIDLookupTable;
+ private ObjectIdentityMap2Int OIDLookupTable;
private int protocolVersion;
private boolean useSubclassMethod;
private SetAccessibleAction setAccessible = new SetAccessibleAction();
diff --git a/java/io/ObjectStreamClass.java b/java/io/ObjectStreamClass.java
index 1ca78ed9f..21a80c392 100644
--- a/java/io/ObjectStreamClass.java
+++ b/java/io/ObjectStreamClass.java
@@ -59,7 +59,6 @@ import java.security.Security;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Hashtable;
-import java.util.Vector;
/**
* @author Tom Tromey (tromey@redhat.com)
@@ -242,37 +241,45 @@ public class ObjectStreamClass implements Serializable
return superClass;
}
-
- // returns an array of ObjectStreamClasses that represent the super
- // classes of CLAZZ and CLAZZ itself in order from most super to
- // CLAZZ. ObjectStreamClass[0] is the highest superclass of CLAZZ
- // that is serializable.
- static ObjectStreamClass[] getObjectStreamClasses(Class<?> clazz)
+ /**
+ * returns an array of ObjectStreamClasses that represent the super
+ * classes of the class represented by this and the class
+ * represented by this itself in order from most super to this.
+ * ObjectStreamClass[0] is the highest superclass of this that is
+ * serializable.
+ *
+ * The result of consecutive calls this hierarchy() will be the same
+ * array instance.
+ *
+ * @return an array of ObjectStreamClass representing the
+ * super-class hierarchy of serializable classes.
+ */
+ ObjectStreamClass[] hierarchy()
{
- ObjectStreamClass osc = ObjectStreamClass.lookup(clazz);
-
- if (osc == null)
- return new ObjectStreamClass[0];
- else
- {
- Vector<ObjectStreamClass> oscs = new Vector<ObjectStreamClass>();
-
- while (osc != null)
- {
- oscs.addElement (osc);
- osc = osc.getSuper();
- }
-
- int count = oscs.size();
- ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[ count ];
-
- for (int i = count - 1; i >= 0; i--)
- sorted_oscs[ count - i - 1 ] = (ObjectStreamClass) oscs.elementAt(i);
-
- return sorted_oscs;
+ ObjectStreamClass[] result = hierarchy;
+ if (result == null)
+ {
+ int d = 0;
+
+ for(ObjectStreamClass osc = this; osc != null; osc = osc.getSuper())
+ d++;
+
+ result = new ObjectStreamClass[d];
+
+ for (ObjectStreamClass osc = this; osc != null; osc = osc.getSuper())
+ {
+ result[--d] = osc;
+ }
+
+ hierarchy = result;
}
+ return result;
}
+ /**
+ * Cache for hierarchy() result.
+ */
+ private ObjectStreamClass[] hierarchy = null;
// Returns an integer that consists of bit-flags that indicate
// properties of the class represented by this ObjectStreamClass.
@@ -305,7 +312,7 @@ public class ObjectStreamClass implements Serializable
* already set UID is found.
*/
void setClass(Class cl, ObjectStreamClass superClass) throws InvalidClassException
- {
+ {hierarchy = null;
this.clazz = cl;
cacheMethods();
@@ -432,6 +439,7 @@ public class ObjectStreamClass implements Serializable
void setSuperclass (ObjectStreamClass osc)
{
superClass = osc;
+ hierarchy = null;
}
void calculateOffsets()
@@ -554,21 +562,62 @@ outer:
return null;
}
+ /**
+ * Helper routine to check if a class was loaded by boot or
+ * application class loader. Classes for which this is not the case
+ * should not be cached since caching prevent class file garbage
+ * collection.
+ *
+ * @param cl a class
+ *
+ * @return true if cl was loaded by boot or application class loader,
+ * false if cl was loaded by a user class loader.
+ */
+ private static boolean loadedByBootOrApplicationClassLoader(Class cl)
+ {
+ ClassLoader l = cl.getClassLoader();
+ return
+ ( l == null /* boot loader */ )
+ || (l == ClassLoader.getSystemClassLoader() /* application loader */);
+ }
+
+ static Hashtable methodCache = new Hashtable();
+
+ static final Class[] readObjectSignature = { ObjectInputStream.class };
+ static final Class[] writeObjectSignature = { ObjectOutputStream.class };
+
private void cacheMethods()
{
- Method[] methods = forClass().getDeclaredMethods();
-
- readObjectMethod = findMethod(methods, "readObject",
- new Class[] { ObjectInputStream.class },
- Void.TYPE, true);
- writeObjectMethod = findMethod(methods, "writeObject",
- new Class[] { ObjectOutputStream.class },
- Void.TYPE, true);
-
- // readResolve and writeReplace can be in parent classes, as long as they
- // are accessible from this class.
- readResolveMethod = findAccessibleMethod("readResolve", forClass());
- writeReplaceMethod = findAccessibleMethod("writeReplace", forClass());
+ Class cl = forClass();
+ Method[] cached = (Method[]) methodCache.get(cl);
+ if (cached == null)
+ {
+ cached = new Method[4];
+ Method[] methods = cl.getDeclaredMethods();
+
+ cached[0] = findMethod(methods, "readObject",
+ readObjectSignature,
+ Void.TYPE, true);
+ cached[1] = findMethod(methods, "writeObject",
+ writeObjectSignature,
+ Void.TYPE, true);
+
+ // readResolve and writeReplace can be in parent classes, as long as they
+ // are accessible from this class.
+ cached[2] = findAccessibleMethod("readResolve", cl);
+ cached[3] = findAccessibleMethod("writeReplace", cl);
+
+ /* put in cache if classes not loaded by user class loader.
+ * For a user class loader, the cache may otherwise grow
+ * without limit.
+ */
+ if (loadedByBootOrApplicationClassLoader(cl))
+ methodCache.put(cl,cached);
+ }
+ readObjectMethod = cached[0];
+ writeObjectMethod = cached[1];
+ readResolveMethod = cached[2];
+ writeReplaceMethod = cached[3];
}
private ObjectStreamClass(Class cl)
@@ -720,152 +769,208 @@ outer:
calculateOffsets();
}
+ static Hashtable uidCache = new Hashtable();
+
// Returns the serial version UID defined by class, or if that
// isn't present, calculates value of serial version UID.
private long getClassUID(Class cl)
{
- try
+ long result = 0;
+ Long cache = (Long) uidCache.get(cl);
+ if (cache != null)
+ result = cache.longValue();
+ else
{
- // Use getDeclaredField rather than getField, since serialVersionUID
- // may not be public AND we only want the serialVersionUID of this
- // class, not a superclass or interface.
- final Field suid = cl.getDeclaredField("serialVersionUID");
- SetAccessibleAction setAccessible = new SetAccessibleAction(suid);
- AccessController.doPrivileged(setAccessible);
- int modifiers = suid.getModifiers();
-
- if (Modifier.isStatic(modifiers)
- && Modifier.isFinal(modifiers)
- && suid.getType() == Long.TYPE)
- return suid.getLong(null);
+ try
+ {
+ result = getClassUIDFromField(cl);
+ }
+ catch (NoSuchFieldException ignore)
+ {
+ try
+ {
+ result = calculateClassUID(cl);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new RuntimeException
+ ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
+ + cl.getName(), e);
+ }
+ catch (IOException ioe)
+ {
+ throw new RuntimeException(ioe);
+ }
+ }
+
+ if (loadedByBootOrApplicationClassLoader(cl))
+ uidCache.put(cl,new Long(result));
}
- catch (NoSuchFieldException ignore)
+ return result;
+ }
+
+ /**
+ * Search for a serialVersionUID field in the given class and read
+ * its value.
+ *
+ * @return the contents of the serialVersionUID field
+ *
+ * @throws NoSuchFieldException if such a field does not exist or is
+ * not static, not final, not of type Long or not accessible.
+ */
+ long getClassUIDFromField(Class cl)
+ throws NoSuchFieldException
+ {
+ long result;
+
+ try
{
+ // Use getDeclaredField rather than getField, since serialVersionUID
+ // may not be public AND we only want the serialVersionUID of this
+ // class, not a superclass or interface.
+ final Field suid = cl.getDeclaredField("serialVersionUID");
+ SetAccessibleAction setAccessible = new SetAccessibleAction(suid);
+ AccessController.doPrivileged(setAccessible);
+ int modifiers = suid.getModifiers();
+
+ if (Modifier.isStatic(modifiers)
+ && Modifier.isFinal(modifiers)
+ && suid.getType() == Long.TYPE)
+ result = suid.getLong(null);
+ else
+ throw new NoSuchFieldException();
}
catch (IllegalAccessException ignore)
{
+ throw new NoSuchFieldException();
}
- // cl didn't define serialVersionUID, so we have to compute it
- try
- {
- MessageDigest md;
- try
- {
- md = MessageDigest.getInstance("SHA");
- }
- catch (NoSuchAlgorithmException e)
- {
- // If a provider already provides SHA, use it; otherwise, use this.
- Gnu gnuProvider = new Gnu();
- Security.addProvider(gnuProvider);
- md = MessageDigest.getInstance("SHA");
- }
-
- DigestOutputStream digest_out =
- new DigestOutputStream(nullOutputStream, md);
- DataOutputStream data_out = new DataOutputStream(digest_out);
-
- data_out.writeUTF(cl.getName());
-
- int modifiers = cl.getModifiers();
- // just look at interesting bits
- modifiers = modifiers & (Modifier.ABSTRACT | Modifier.FINAL
- | Modifier.INTERFACE | Modifier.PUBLIC);
- data_out.writeInt(modifiers);
-
- // Pretend that an array has no interfaces, because when array
- // serialization was defined (JDK 1.1), arrays didn't have it.
- if (! cl.isArray())
- {
- Class[] interfaces = cl.getInterfaces();
- Arrays.sort(interfaces, interfaceComparator);
- for (int i = 0; i < interfaces.length; i++)
- data_out.writeUTF(interfaces[i].getName());
- }
-
- Field field;
- Field[] fields = cl.getDeclaredFields();
- Arrays.sort(fields, memberComparator);
- for (int i = 0; i < fields.length; i++)
- {
- field = fields[i];
- modifiers = field.getModifiers();
- if (Modifier.isPrivate(modifiers)
- && (Modifier.isStatic(modifiers)
- || Modifier.isTransient(modifiers)))
- continue;
-
- data_out.writeUTF(field.getName());
- data_out.writeInt(modifiers);
- data_out.writeUTF(TypeSignature.getEncodingOfClass (field.getType()));
- }
-
- // write class initializer method if present
- if (VMObjectStreamClass.hasClassInitializer(cl))
- {
- data_out.writeUTF("<clinit>");
- data_out.writeInt(Modifier.STATIC);
- data_out.writeUTF("()V");
- }
-
- Constructor constructor;
- Constructor[] constructors = cl.getDeclaredConstructors();
- Arrays.sort (constructors, memberComparator);
- for (int i = 0; i < constructors.length; i++)
- {
- constructor = constructors[i];
- modifiers = constructor.getModifiers();
- if (Modifier.isPrivate(modifiers))
- continue;
-
- data_out.writeUTF("<init>");
- data_out.writeInt(modifiers);
-
- // the replacement of '/' with '.' was needed to make computed
- // SUID's agree with those computed by JDK
- data_out.writeUTF
- (TypeSignature.getEncodingOfConstructor(constructor).replace('/','.'));
- }
-
- Method method;
- Method[] methods = cl.getDeclaredMethods();
- Arrays.sort(methods, memberComparator);
- for (int i = 0; i < methods.length; i++)
- {
- method = methods[i];
- modifiers = method.getModifiers();
- if (Modifier.isPrivate(modifiers))
- continue;
-
- data_out.writeUTF(method.getName());
- data_out.writeInt(modifiers);
-
- // the replacement of '/' with '.' was needed to make computed
- // SUID's agree with those computed by JDK
- data_out.writeUTF
- (TypeSignature.getEncodingOfMethod(method).replace('/', '.'));
- }
-
- data_out.close();
- byte[] sha = md.digest();
- long result = 0;
- int len = sha.length < 8 ? sha.length : 8;
- for (int i = 0; i < len; i++)
- result += (long) (sha[i] & 0xFF) << (8 * i);
+ return result;
+ }
- return result;
+ /**
+ * Calculate class serial version UID for a class that does not
+ * define serialVersionUID:
+ *
+ * @param cl a class
+ *
+ * @return the calculated serial varsion UID.
+ *
+ * @throws NoSuchAlgorithmException if SHA algorithm not found
+ *
+ * @throws IOException if writing to the DigestOutputStream causes
+ * an IOException.
+ */
+ long calculateClassUID(Class cl)
+ throws NoSuchAlgorithmException, IOException
+ {
+ long result;
+ MessageDigest md;
+ try
+ {
+ md = MessageDigest.getInstance("SHA");
}
catch (NoSuchAlgorithmException e)
{
- throw new RuntimeException
- ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
- + cl.getName(), e);
+ // If a provider already provides SHA, use it; otherwise, use this.
+ Gnu gnuProvider = new Gnu();
+ Security.addProvider(gnuProvider);
+ md = MessageDigest.getInstance("SHA");
+ }
+
+ DigestOutputStream digest_out =
+ new DigestOutputStream(nullOutputStream, md);
+ DataOutputStream data_out = new DataOutputStream(digest_out);
+
+ data_out.writeUTF(cl.getName());
+
+ int modifiers = cl.getModifiers();
+ // just look at interesting bits
+ modifiers = modifiers & (Modifier.ABSTRACT | Modifier.FINAL
+ | Modifier.INTERFACE | Modifier.PUBLIC);
+ data_out.writeInt(modifiers);
+
+ // Pretend that an array has no interfaces, because when array
+ // serialization was defined (JDK 1.1), arrays didn't have it.
+ if (! cl.isArray())
+ {
+ Class[] interfaces = cl.getInterfaces();
+ Arrays.sort(interfaces, interfaceComparator);
+ for (int i = 0; i < interfaces.length; i++)
+ data_out.writeUTF(interfaces[i].getName());
+ }
+
+ Field field;
+ Field[] fields = cl.getDeclaredFields();
+ Arrays.sort(fields, memberComparator);
+ for (int i = 0; i < fields.length; i++)
+ {
+ field = fields[i];
+ modifiers = field.getModifiers();
+ if (Modifier.isPrivate(modifiers)
+ && (Modifier.isStatic(modifiers)
+ || Modifier.isTransient(modifiers)))
+ continue;
+
+ data_out.writeUTF(field.getName());
+ data_out.writeInt(modifiers);
+ data_out.writeUTF(TypeSignature.getEncodingOfClass (field.getType()));
+ }
+
+ // write class initializer method if present
+ if (VMObjectStreamClass.hasClassInitializer(cl))
+ {
+ data_out.writeUTF("<clinit>");
+ data_out.writeInt(Modifier.STATIC);
+ data_out.writeUTF("()V");
}
- catch (IOException ioe)
+
+ Constructor constructor;
+ Constructor[] constructors = cl.getDeclaredConstructors();
+ Arrays.sort (constructors, memberComparator);
+ for (int i = 0; i < constructors.length; i++)
+ {
+ constructor = constructors[i];
+ modifiers = constructor.getModifiers();
+ if (Modifier.isPrivate(modifiers))
+ continue;
+
+ data_out.writeUTF("<init>");
+ data_out.writeInt(modifiers);
+
+ // the replacement of '/' with '.' was needed to make computed
+ // SUID's agree with those computed by JDK
+ data_out.writeUTF
+ (TypeSignature.getEncodingOfConstructor(constructor).replace('/','.'));
+ }
+
+ Method method;
+ Method[] methods = cl.getDeclaredMethods();
+ Arrays.sort(methods, memberComparator);
+ for (int i = 0; i < methods.length; i++)
{
- throw new RuntimeException(ioe);
+ method = methods[i];
+ modifiers = method.getModifiers();
+ if (Modifier.isPrivate(modifiers))
+ continue;
+
+ data_out.writeUTF(method.getName());
+ data_out.writeInt(modifiers);
+
+ // the replacement of '/' with '.' was needed to make computed
+ // SUID's agree with those computed by JDK
+ data_out.writeUTF
+ (TypeSignature.getEncodingOfMethod(method).replace('/', '.'));
}
+
+ data_out.close();
+ byte[] sha = md.digest();
+ result = 0;
+ int len = sha.length < 8 ? sha.length : 8;
+ for (int i = 0; i < len; i++)
+ result += (long) (sha[i] & 0xFF) << (8 * i);
+
+ return result;
}
/**
diff --git a/java/io/ObjectStreamField.java b/java/io/ObjectStreamField.java
index b0cac5015..91f557870 100644
--- a/java/io/ObjectStreamField.java
+++ b/java/io/ObjectStreamField.java
@@ -65,7 +65,7 @@ public class ObjectStreamField
private boolean unshared;
private boolean persistent = false;
private boolean toset = true;
- private Field field;
+ Field field;
ObjectStreamField (Field field)
{
diff --git a/java/io/PrintStream.java b/java/io/PrintStream.java
index 9726ccdba..2d747c8c8 100644
--- a/java/io/PrintStream.java
+++ b/java/io/PrintStream.java
@@ -71,7 +71,7 @@ public class PrintStream extends FilterOutputStream implements Appendable
// Line separator string.
private static final char[] line_separator
- = SystemProperties.getProperty("line.separator").toCharArray();
+ = SystemProperties.getProperty("line.separator", "\n").toCharArray();
/**
* Encoding name
diff --git a/java/lang/management/ManagementFactory.java b/java/lang/management/ManagementFactory.java
index d6727ea10..d9a02ee23 100644
--- a/java/lang/management/ManagementFactory.java
+++ b/java/lang/management/ManagementFactory.java
@@ -67,6 +67,49 @@ import javax.management.NotCompliantMBeanException;
* <li>Calling the appropriate static method of this factory.
* </li>
* </ol>
+ * <h2>Open Data Types</h2>
+ * <p>
+ * The data types used by the management beans are restricted
+ * to <emph>open</emph> data types to aid interoperability. This
+ * allows the beans to be accessed remotely, including from non-Java
+ * clients. Below is a table which lists the types used by the beans
+ * on the left, and the types they are converted to when returned via
+ * a bean server on the right. Type information is provided for each
+ * bean by obtaining its instance of {@link javax.management.MBeanInfo}.
+ * </p>
+ * <table>
+ * <th><td>Data Type Used</td><td>Data Type Returned</td></th>
+ * <tr>
+ * <td>Primitive types (<code>int</code>, <code>char</code>, etc.)</td>
+ * <td>Same</td>
+ * </tr><tr>
+ * <td>Wrapper classes ({@link{java.lang.Integer},
+ * @link{java.lang.Character}, etc.)</td>
+ * <td>Same</td>
+ * </tr><tr>
+ * <td>An {@link java.lang.Enum}</td>
+ * <td>The <code>name</code> of the enumeration constant</td>
+ * </tr><tr>
+ * <td>An array of type <code>E</code></td>
+ * <td>An array of the same dimensions with this mapping applied
+ * to <code>E</code>.</td>
+ * </tr><tr>
+ * <td>A class with `getter' methods and a
+ * <code>from({@link javax.management.openmbean.CompositeData})</code>
+ * method.</td>
+ * <td>The equivalent {@link javax.management.openmbean.CompositeData}
+ * instance, specified by the <code>from</code> method.</td>
+ * </tr><tr>
+ * <td>A map with keys of type <code>K</code> and values of
+ * type <code>V</code>.</td>
+ * <td>A {@link javax.management.openmbean.TabularData} instance,
+ * with the row type containing two items, <code>"key"</code> and
+ * <code>"value"</code> with the types <code>K</code> and <code>V</code>
+ * respectively (with translation applied).</td>
+ * </tr><tr>
+ * <td>A list of type <code>E</code>.</td>
+ * <td>An array with this mapping applied to <code>E</code>.</td>
+ * </tr></table>
*
* @author Andrew John Hughes (gnu_andrew@member.fsf.org)
* @since 1.5
diff --git a/java/lang/ref/Reference.java b/java/lang/ref/Reference.java
index 8a7501863..ce224b891 100644
--- a/java/lang/ref/Reference.java
+++ b/java/lang/ref/Reference.java
@@ -1,5 +1,5 @@
/* java.lang.ref.Reference
- Copyright (C) 1999, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -82,7 +82,7 @@ public abstract class Reference<T>
* The queue this reference is registered on. This is null, if this
* wasn't registered to any queue or reference was already enqueued.
*/
- ReferenceQueue<? super T> queue;
+ volatile ReferenceQueue<? super T> queue;
/**
* Link to the next entry on the queue. If this is null, this
@@ -91,7 +91,7 @@ public abstract class Reference<T>
* (not to null, that value is used to mark a not enqueued
* reference).
*/
- Reference nextOnQueue;
+ volatile Reference nextOnQueue;
/**
* This lock should be taken by the garbage collector, before
@@ -166,11 +166,10 @@ public abstract class Reference<T>
*/
public boolean enqueue()
{
- if (queue != null && nextOnQueue == null)
+ ReferenceQueue q = queue;
+ if (q != null)
{
- queue.enqueue(this);
- queue = null;
- return true;
+ return q.enqueue(this);
}
return false;
}
diff --git a/java/lang/ref/ReferenceQueue.java b/java/lang/ref/ReferenceQueue.java
index 189b81b17..281628779 100644
--- a/java/lang/ref/ReferenceQueue.java
+++ b/java/lang/ref/ReferenceQueue.java
@@ -1,5 +1,5 @@
/* java.lang.ref.ReferenceQueue
- Copyright (C) 1999, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -63,6 +63,12 @@ public class ReferenceQueue<T>
private Reference<? extends T> first;
/**
+ * This is the lock that protects our linked list and is used to signal
+ * a thread waiting in remove().
+ */
+ private final Object lock = new Object();
+
+ /**
* Creates a new empty reference queue.
*/
public ReferenceQueue()
@@ -76,7 +82,7 @@ public class ReferenceQueue<T>
* @return a reference on the queue, if there is one,
* <code>null</code> otherwise.
*/
- public synchronized Reference<? extends T> poll()
+ public Reference<? extends T> poll()
{
return dequeue();
}
@@ -84,14 +90,23 @@ public class ReferenceQueue<T>
/**
* This is called by reference to enqueue itself on this queue.
* @param ref the reference that should be enqueued.
+ * @return true if successful, false if not.
*/
- synchronized void enqueue(Reference<? extends T> ref)
- {
- /* last reference will point to itself */
- ref.nextOnQueue = first == null ? ref : first;
- first = ref;
- /* this wakes only one remove thread. */
- notify();
+ final boolean enqueue(Reference<? extends T> ref)
+ {
+ synchronized (lock)
+ {
+ if (ref.queue != this)
+ return false;
+
+ /* last reference will point to itself */
+ ref.nextOnQueue = first == null ? ref : first;
+ ref.queue = null;
+ first = ref;
+ /* this wakes only one remove thread. */
+ lock.notify();
+ return true;
+ }
}
/**
@@ -100,13 +115,16 @@ public class ReferenceQueue<T>
*/
private Reference<? extends T> dequeue()
{
- if (first == null)
- return null;
-
- Reference<? extends T> result = first;
- first = (first == first.nextOnQueue) ? null : first.nextOnQueue;
- result.nextOnQueue = null;
- return result;
+ synchronized (lock)
+ {
+ if (first == null)
+ return null;
+
+ Reference<? extends T> result = first;
+ first = (first == first.nextOnQueue) ? null : first.nextOnQueue;
+ result.nextOnQueue = null;
+ return result;
+ }
}
/**
@@ -118,12 +136,13 @@ public class ReferenceQueue<T>
* <code>null</code> if timeout period expired.
* @exception InterruptedException if the wait was interrupted.
*/
- public synchronized Reference<? extends T> remove(long timeout)
+ public Reference<? extends T> remove(long timeout)
throws InterruptedException
{
- if (first == null)
+ synchronized (lock)
{
- wait(timeout);
+ if (first == null)
+ lock.wait(timeout);
}
return dequeue();
diff --git a/java/math/BigInteger.java b/java/math/BigInteger.java
index 0a683f7b7..c897d8bf4 100644
--- a/java/math/BigInteger.java
+++ b/java/math/BigInteger.java
@@ -1,5 +1,5 @@
/* java.math.BigInteger -- Arbitary precision integers
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -198,8 +198,20 @@ public class BigInteger extends Number implements Comparable<BigInteger>
private void init(int numBits, Random rnd)
{
int highbits = numBits & 31;
+ // minimum number of bytes to store the above number of bits
+ int highBitByteCount = (highbits + 7) / 8;
+ // number of bits to discard from the last byte
+ int discardedBitCount = highbits % 8;
+ if (discardedBitCount != 0)
+ discardedBitCount = 8 - discardedBitCount;
+ byte[] highBitBytes = new byte[highBitByteCount];
if (highbits > 0)
- highbits = rnd.nextInt() >>> (32 - highbits);
+ {
+ rnd.nextBytes(highBitBytes);
+ highbits = (highBitBytes[highBitByteCount - 1] & 0xFF) >>> discardedBitCount;
+ for (int i = highBitByteCount - 2; i >= 0; i--)
+ highbits = (highbits << 8) | (highBitBytes[i] & 0xFF);
+ }
int nwords = numBits / 32;
while (highbits == 0 && nwords > 0)
@@ -226,8 +238,13 @@ public class BigInteger extends Number implements Comparable<BigInteger>
this(bitLength, rnd);
// Keep going until we find a probable prime.
+ BigInteger result;
while (true)
{
+ // ...but first ensure that BI has bitLength bits
+ result = setBit(bitLength - 1);
+ this.ival = result.ival;
+ this.words = result.words;
if (isProbablePrime(certainty))
return;
@@ -1583,24 +1600,31 @@ public class BigInteger extends Number implements Comparable<BigInteger>
// but slightly more expensive, for little practical gain.
if (len <= 15 && radix <= 16)
return valueOf(Long.parseLong(s, radix));
-
+
+ int i, digit;
+ boolean negative;
+ byte[] bytes;
+ char ch = s.charAt(0);
+ if (ch == '-')
+ {
+ negative = true;
+ i = 1;
+ bytes = new byte[len - 1];
+ }
+ else
+ {
+ negative = false;
+ i = 0;
+ bytes = new byte[len];
+ }
int byte_len = 0;
- byte[] bytes = new byte[len];
- boolean negative = false;
- for (int i = 0; i < len; i++)
+ for ( ; i < len; i++)
{
- char ch = s.charAt(i);
- if (ch == '-')
- negative = true;
- else if (ch == '_' || (byte_len == 0 && (ch == ' ' || ch == '\t')))
- continue;
- else
- {
- int digit = Character.digit(ch, radix);
- if (digit < 0)
- break;
- bytes[byte_len++] = (byte) digit;
- }
+ ch = s.charAt(i);
+ digit = Character.digit(ch, radix);
+ if (digit < 0)
+ throw new NumberFormatException();
+ bytes[byte_len++] = (byte) digit;
}
return valueOf(bytes, byte_len, negative, radix);
}
diff --git a/java/net/SocketPermission.java b/java/net/SocketPermission.java
index 723ccc7a5..97e93dcbb 100644
--- a/java/net/SocketPermission.java
+++ b/java/net/SocketPermission.java
@@ -164,24 +164,69 @@ public final class SocketPermission extends Permission implements Serializable
*/
public SocketPermission(String hostport, String actions)
{
- super(hostport);
+ super(processHostport(hostport));
- setHostPort(hostport);
+ setHostPort(getName());
setActions(actions);
}
/**
+ * There are two cases in which hostport needs rewriting before
+ * being passed to the superclass constructor. If hostport is an
+ * empty string then it is substituted with "localhost". And if
+ * the host part of hostport is a literal IPv6 address in the full
+ * uncompressed form not enclosed with "[" and "]" then we enclose
+ * it with them.
+ */
+ private static String processHostport(String hostport)
+ {
+ if (hostport.length() == 0)
+ return "localhost";
+
+ if (hostport.charAt(0) == '[')
+ return hostport;
+
+ int colons = 0, last_colon = 0;
+ for (int i = 0; i < hostport.length(); i++)
+ {
+ if (hostport.charAt(i) == ':')
+ {
+ if (i - last_colon == 1)
+ throw new IllegalArgumentException("Ambiguous hostport part");
+ colons++;
+ last_colon = i;
+ }
+ }
+
+ switch (colons)
+ {
+ case 0:
+ case 1:
+ // a hostname or IPv4 address
+ return hostport;
+
+ case 7:
+ // an IPv6 address with no ports
+ return "[" + hostport + "]";
+
+ case 8:
+ // an IPv6 address with ports
+ return "[" + hostport.substring(0, last_colon) + "]"
+ + hostport.substring(last_colon);
+
+ default:
+ throw new IllegalArgumentException("Ambiguous hostport part");
+ }
+ }
+
+ /**
* Parse the hostport argument to the constructor.
*/
private void setHostPort(String hostport)
{
// Split into host and ports
String ports;
- if (hostport.length() == 0)
- {
- host = ports = "";
- }
- else if (hostport.charAt(0) == '[')
+ if (hostport.charAt(0) == '[')
{
// host is a bracketed IPv6 address
int end = hostport.indexOf("]");
@@ -211,8 +256,6 @@ public final class SocketPermission extends Permission implements Serializable
ports = hostport.substring(sep + 1);
}
}
- if (ports.indexOf(":") != -1)
- throw new IllegalArgumentException("Unexpected ':'");
// Parse and validate the ports
if (ports.length() == 0)
diff --git a/java/security/AlgorithmParameterGenerator.java b/java/security/AlgorithmParameterGenerator.java
index e33fbaf81..e2a17d4bf 100644
--- a/java/security/AlgorithmParameterGenerator.java
+++ b/java/security/AlgorithmParameterGenerator.java
@@ -40,6 +40,7 @@ package java.security;
import gnu.java.security.Engine;
+import java.lang.reflect.InvocationTargetException;
import java.security.spec.AlgorithmParameterSpec;
/**
@@ -97,26 +98,29 @@ public class AlgorithmParameterGenerator
* Returns a new <code>AlgorithmParameterGenerator</code> instance which
* generates algorithm parameters for the specified algorithm.
*
- * @param algorithm
- * the name of algorithm to use.
+ * @param algorithm the name of algorithm to use.
* @return the new instance.
- * @throws NoSuchAlgorithmException
- * if <code>algorithm</code> is not implemented by any provider.
+ * @throws NoSuchAlgorithmException if <code>algorithm</code> is not
+ * implemented by any provider.
+ * @throws IllegalArgumentException if <code>algorithm</code> is
+ * <code>null</code> or is an empty string.
*/
public static AlgorithmParameterGenerator getInstance(String algorithm)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
Provider[] p = Security.getProviders();
+ NoSuchAlgorithmException lastException = null;
for (int i = 0; i < p.length; i++)
try
{
return getInstance(algorithm, p[i]);
}
- catch (NoSuchAlgorithmException e)
- {
- // Ignore.
- }
-
+ catch (NoSuchAlgorithmException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new NoSuchAlgorithmException(algorithm);
}
@@ -124,27 +128,27 @@ public class AlgorithmParameterGenerator
* Returns a new <code>AlgorithmParameterGenerator</code> instance which
* generates algorithm parameters for the specified algorithm.
*
- * @param algorithm
- * the name of algorithm to use.
- * @param provider
- * the name of the {@link Provider} to use.
+ * @param algorithm the name of algorithm to use.
+ * @param provider the name of the {@link Provider} to use.
* @return the new instance.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by the named provider.
- * @throws NoSuchProviderException
- * if the named provider was not found.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by the
+ * named provider.
+ * @throws NoSuchProviderException if the named provider was not found.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code> or empty.
*/
public static AlgorithmParameterGenerator getInstance(String algorithm,
- String provider)
- throws NoSuchAlgorithmException, NoSuchProviderException
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException
{
- if (provider == null || provider.length() == 0)
- throw new IllegalArgumentException("Illegal provider");
-
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
+ provider = provider.trim();
+ if (provider.length() == 0)
+ throw new IllegalArgumentException("provider MUST NOT be empty");
Provider p = Security.getProvider(provider);
if (p == null)
throw new NoSuchProviderException(provider);
-
return getInstance(algorithm, p);
}
@@ -152,38 +156,50 @@ public class AlgorithmParameterGenerator
* Returns a new <code>AlgorithmParameterGenerator</code> instance which
* generates algorithm parameters for the specified algorithm.
*
- * @param algorithm
- * the name of algorithm to use.
- * @param provider
- * the {@link Provider} to use.
+ * @param algorithm the name of algorithm to use.
+ * @param provider the {@link Provider} to use.
* @return the new instance.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by {@link Provider}.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by
+ * {@link Provider}.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>algorithm</code> is an empty string.
* @since 1.4
* @see Provider
*/
public static AlgorithmParameterGenerator getInstance(String algorithm,
Provider provider)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
- if (provider == null)
- throw new IllegalArgumentException("Illegal provider");
-
+ StringBuilder sb = new StringBuilder()
+ .append("AlgorithmParameterGenerator for algorithm [")
+ .append(algorithm).append("] from provider[")
+ .append(provider).append("] could not be created");
+ Throwable cause;
try
{
- return new AlgorithmParameterGenerator(
- (AlgorithmParameterGeneratorSpi) Engine.getInstance(
- ALGORITHM_PARAMETER_GENERATOR, algorithm, provider),
- provider, algorithm);
+ Object spi = Engine.getInstance(ALGORITHM_PARAMETER_GENERATOR,
+ algorithm,
+ provider);
+ return new AlgorithmParameterGenerator((AlgorithmParameterGeneratorSpi) spi,
+ provider,
+ algorithm);
}
- catch (java.lang.reflect.InvocationTargetException ite)
+ catch (InvocationTargetException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ cause = x.getCause();
+ if (cause instanceof NoSuchAlgorithmException)
+ throw (NoSuchAlgorithmException) cause;
+ if (cause == null)
+ cause = x;
}
- catch (ClassCastException cce)
+ catch (ClassCastException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ cause = x;
}
+ NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
+ x.initCause(cause);
+ throw x;
}
/** @return the {@link Provider} of this generator. */
diff --git a/java/security/AlgorithmParameters.java b/java/security/AlgorithmParameters.java
index 911c566c8..f5e5063a1 100644
--- a/java/security/AlgorithmParameters.java
+++ b/java/security/AlgorithmParameters.java
@@ -41,6 +41,7 @@ package java.security;
import gnu.java.security.Engine;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException;
@@ -91,106 +92,115 @@ public class AlgorithmParameters
/**
* Returns a new instance of <code>AlgorithmParameters</code> representing
* the specified algorithm parameters.
+ * <p>
+ * The returned <code>AlgorithmParameters</code> must still be initialized
+ * with an <code>init()</code> method.
*
- * <p>The returned <code>AlgorithmParameters</code> must still be initialized
- * with an <code>init()</code> method.</p>
- *
- * @param algorithm
- * the algorithm to use.
+ * @param algorithm the algorithm to use.
* @return the new instance repesenting the desired algorithm.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by any provider.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by any
+ * provider.
+ * @throws IllegalArgumentException if <code>algorithm</code> is
+ * <code>null</code> or is an empty string.
*/
public static AlgorithmParameters getInstance(String algorithm)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
Provider[] p = Security.getProviders();
-
+ NoSuchAlgorithmException lastException = null;
for (int i = 0; i < p.length; i++)
try
{
return getInstance(algorithm, p[i]);
}
- catch (NoSuchAlgorithmException e)
- {
- // Ignore this.
- }
-
+ catch (NoSuchAlgorithmException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new NoSuchAlgorithmException(algorithm);
}
/**
* Returns a new instance of <code>AlgorithmParameters</code> representing
* the specified algorithm parameters from a named provider.
+ * <p>
+ * The returned <code>AlgorithmParameters</code> must still be intialized
+ * with an <code>init()</code> method.
+ * </p>
*
- * <p>The returned <code>AlgorithmParameters</code> must still be intialized
- * with an <code>init()</code> method.</p>
- *
- * @param algorithm
- * the algorithm to use.
- * @param provider
- * the name of the {@link Provider} to use.
+ * @param algorithm the algorithm to use.
+ * @param provider the name of the {@link Provider} to use.
* @return the new instance repesenting the desired algorithm.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by the named provider.
- * @throws NoSuchProviderException
- * if the named provider was not found.
- * @throws IllegalArgumentException
- * if <code>provider</code> is <code>null</code> or is an empty
- * string.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by the
+ * named provider.
+ * @throws NoSuchProviderException if the named provider was not found.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code> or empty.
*/
- public static AlgorithmParameters getInstance(String algorithm, String provider)
- throws NoSuchAlgorithmException, NoSuchProviderException
+ public static AlgorithmParameters getInstance(String algorithm,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException
{
- if (provider == null || provider.length() == 0)
- throw new IllegalArgumentException("Illegal provider");
-
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
+ provider = provider.trim();
+ if (provider.length() == 0)
+ throw new IllegalArgumentException("provider MUST NOT be empty");
Provider p = Security.getProvider(provider);
if (p == null)
throw new NoSuchProviderException(provider);
-
return getInstance(algorithm, p);
}
/**
* Returns a new instance of <code>AlgorithmParameters</code> representing
* the specified algorithm parameters from the specified {@link Provider}.
+ * <p>
+ * The returned <code>AlgorithmParameters</code> must still be intialized
+ * with an <code>init()</code> method.
*
- * <p>The returned <code>AlgorithmParameters</code> must still be intialized
- * with an <code>init()</code> method.</p>
- *
- * @param algorithm
- * the algorithm to use.
- * @param provider
- * the {@link Provider} to use.
+ * @param algorithm the algorithm to use.
+ * @param provider the {@link Provider} to use.
* @return the new instance repesenting the desired algorithm.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by the {@link Provider}.
- * @throws IllegalArgumentException
- * if <code>provider</code> is <code>null</code>.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by the
+ * {@link Provider}.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>algorithm</code> is an empty string.
* @since 1.4
*/
public static AlgorithmParameters getInstance(String algorithm,
Provider provider)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
- if (provider == null)
- throw new IllegalArgumentException("Illegal provider");
-
+ StringBuilder sb = new StringBuilder("AlgorithmParameters for algorithm [")
+ .append(algorithm).append("] from provider[")
+ .append(provider).append("] could not be created");
+ Throwable cause;
try
{
- return new AlgorithmParameters((AlgorithmParametersSpi)
- Engine.getInstance(ALGORITHM_PARAMETERS, algorithm, provider),
- provider, algorithm);
+ Object spi = Engine.getInstance(ALGORITHM_PARAMETERS, algorithm, provider);
+ return new AlgorithmParameters((AlgorithmParametersSpi) spi,
+ provider,
+ algorithm);
}
- catch (java.lang.reflect.InvocationTargetException ite)
+ catch (InvocationTargetException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ cause = x.getCause();
+ if (cause instanceof NoSuchAlgorithmException)
+ throw (NoSuchAlgorithmException) cause;
+ if (cause == null)
+ cause = x;
}
- catch (ClassCastException cce)
+ catch (ClassCastException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ cause = x;
}
+ NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
+ x.initCause(cause);
+ throw x;
}
/** @return the provider of this parameter object. */
diff --git a/java/security/KeyFactory.java b/java/security/KeyFactory.java
index 1ecfd2f72..043dd59a1 100644
--- a/java/security/KeyFactory.java
+++ b/java/security/KeyFactory.java
@@ -40,6 +40,7 @@ package java.security;
import gnu.java.security.Engine;
+import java.lang.reflect.InvocationTargetException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
@@ -93,26 +94,29 @@ public class KeyFactory
* Returns a new instance of <code>KeyFactory</code> representing the
* specified key factory.
*
- * @param algorithm
- * the name of algorithm to use.
+ * @param algorithm the name of algorithm to use.
* @return a new instance repesenting the desired algorithm.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by any provider.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by any
+ * provider.
+ * @throws IllegalArgumentException if <code>algorithm</code> is
+ * <code>null</code> or is an empty string.
*/
public static KeyFactory getInstance(String algorithm)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
Provider[] p = Security.getProviders();
+ NoSuchAlgorithmException lastException = null;
for (int i = 0; i < p.length; i++)
try
{
return getInstance(algorithm, p[i]);
}
- catch (NoSuchAlgorithmException e)
- {
- // Ignore.
- }
-
+ catch (NoSuchAlgorithmException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new NoSuchAlgorithmException(algorithm);
}
@@ -120,29 +124,26 @@ public class KeyFactory
* Returns a new instance of <code>KeyFactory</code> representing the
* specified key factory from the specified provider.
*
- * @param algorithm
- * the name of algorithm to use.
- * @param provider
- * the name of the provider to use.
+ * @param algorithm the name of algorithm to use.
+ * @param provider the name of the provider to use.
* @return a new instance repesenting the desired algorithm.
- * @throws IllegalArgumentException
- * if <code>provider</code> is <code>null</code> or is an empty
- * string.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by the named provider.
- * @throws NoSuchProviderException
- * if the named provider was not found.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by the
+ * named provider.
+ * @throws NoSuchProviderException if the named provider was not found.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code> or empty.
*/
public static KeyFactory getInstance(String algorithm, String provider)
- throws NoSuchAlgorithmException, NoSuchProviderException
+ throws NoSuchAlgorithmException, NoSuchProviderException
{
- if (provider == null || provider.length() == 0)
- throw new IllegalArgumentException("Illegal provider");
-
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
+ provider = provider.trim();
+ if (provider.length() == 0)
+ throw new IllegalArgumentException("provider MUST NOT be empty");
Provider p = Security.getProvider(provider);
if (p == null)
throw new NoSuchProviderException(provider);
-
return getInstance(algorithm, p);
}
@@ -150,38 +151,44 @@ public class KeyFactory
* Returns a new instance of <code>KeyFactory</code> representing the
* specified key factory from the designated {@link Provider}.
*
- * @param algorithm
- * the name of algorithm to use.
- * @param provider
- * the {@link Provider} to use.
+ * @param algorithm the name of algorithm to use.
+ * @param provider the {@link Provider} to use.
* @return a new instance repesenting the desired algorithm.
- * @throws IllegalArgumentException
- * if <code>provider</code> is <code>null</code>.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by {@link Provider}.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by
+ * {@link Provider}.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>algorithm</code> is an empty string.
* @since 1.4
* @see Provider
*/
public static KeyFactory getInstance(String algorithm, Provider provider)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
- if (provider == null)
- throw new IllegalArgumentException("Illegal provider");
-
+ StringBuilder sb = new StringBuilder("KeyFactory for algorithm [")
+ .append(algorithm).append("] from provider[")
+ .append(provider).append("] could not be created");
+ Throwable cause;
try
{
- return new KeyFactory((KeyFactorySpi)
- Engine.getInstance(KEY_FACTORY, algorithm, provider),
- provider, algorithm);
+ Object spi = Engine.getInstance(KEY_FACTORY, algorithm, provider);
+ return new KeyFactory((KeyFactorySpi) spi, provider, algorithm);
}
- catch (java.lang.reflect.InvocationTargetException ite)
+ catch (InvocationTargetException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ cause = x.getCause();
+ if (cause instanceof NoSuchAlgorithmException)
+ throw (NoSuchAlgorithmException) cause;
+ if (cause == null)
+ cause = x;
}
- catch (ClassCastException cce)
+ catch (ClassCastException x)
{
- throw new NoSuchAlgorithmException(algorithm);
- }
+ cause = x;
+ }
+ NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
+ x.initCause(cause);
+ throw x;
}
/**
diff --git a/java/security/KeyPairGenerator.java b/java/security/KeyPairGenerator.java
index 357d7a75f..6974035fd 100644
--- a/java/security/KeyPairGenerator.java
+++ b/java/security/KeyPairGenerator.java
@@ -40,6 +40,7 @@ package java.security;
import gnu.java.security.Engine;
+import java.lang.reflect.InvocationTargetException;
import java.security.spec.AlgorithmParameterSpec;
/**
@@ -90,28 +91,29 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi
* Returns a new instance of <code>KeyPairGenerator</code> which generates
* key-pairs for the specified algorithm.
*
- * @param algorithm
- * the name of the algorithm to use.
+ * @param algorithm the name of the algorithm to use.
* @return a new instance repesenting the desired algorithm.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by any provider.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by any
+ * provider.
+ * @throws IllegalArgumentException if <code>algorithm</code> is
+ * <code>null</code> or is an empty string.
*/
public static KeyPairGenerator getInstance(String algorithm)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
Provider[] p = Security.getProviders();
+ NoSuchAlgorithmException lastException = null;
for (int i = 0; i < p.length; i++)
- {
- try
- {
- return getInstance(algorithm, p[i]);
- }
- catch (NoSuchAlgorithmException e)
- {
- // Ignored.
- }
- }
-
+ try
+ {
+ return getInstance(algorithm, p[i]);
+ }
+ catch (NoSuchAlgorithmException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new NoSuchAlgorithmException(algorithm);
}
@@ -119,23 +121,26 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi
* Returns a new instance of <code>KeyPairGenerator</code> which generates
* key-pairs for the specified algorithm from a named provider.
*
- * @param algorithm
- * the name of the algorithm to use.
- * @param provider
- * the name of a {@link Provider} to use.
+ * @param algorithm the name of the algorithm to use.
+ * @param provider the name of a {@link Provider} to use.
* @return a new instance repesenting the desired algorithm.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by the named provider.
- * @throws NoSuchProviderException
- * if the named provider was not found.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by the
+ * named provider.
+ * @throws NoSuchProviderException if the named provider was not found.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code> or empty.
*/
public static KeyPairGenerator getInstance(String algorithm, String provider)
- throws NoSuchAlgorithmException, NoSuchProviderException
+ throws NoSuchAlgorithmException, NoSuchProviderException
{
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
+ provider = provider.trim();
+ if (provider.length() == 0)
+ throw new IllegalArgumentException("provider MUST NOT be empty");
Provider p = Security.getProvider(provider);
if (p == null)
throw new NoSuchProviderException(provider);
-
return getInstance(algorithm, p);
}
@@ -148,10 +153,11 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi
* @param provider
* the {@link Provider} to use.
* @return a new insatnce repesenting the desired algorithm.
- * @throws IllegalArgumentException
- * if <code>provider</code> is <code>null</code>.
* @throws NoSuchAlgorithmException
* if the algorithm is not implemented by the {@link Provider}.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>algorithm</code> is an empty string.
* @since 1.4
* @see Provider
*/
@@ -159,20 +165,27 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi
Provider provider)
throws NoSuchAlgorithmException
{
- if (provider == null)
- throw new IllegalArgumentException("Illegal provider");
-
- Object o = null;
+ StringBuilder sb = new StringBuilder("KeyPairGenerator for algorithm [")
+ .append(algorithm).append("] from provider[")
+ .append(provider).append("] ");
+ Object o;
try
{
o = Engine.getInstance(KEY_PAIR_GENERATOR, algorithm, provider);
}
- catch (java.lang.reflect.InvocationTargetException ite)
+ catch (InvocationTargetException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ Throwable cause = x.getCause();
+ if (cause instanceof NoSuchAlgorithmException)
+ throw (NoSuchAlgorithmException) cause;
+ if (cause == null)
+ cause = x;
+ sb.append("could not be created");
+ NoSuchAlgorithmException y = new NoSuchAlgorithmException(sb.toString());
+ y.initCause(cause);
+ throw y;
}
-
- KeyPairGenerator result = null;
+ KeyPairGenerator result;
if (o instanceof KeyPairGenerator)
{
result = (KeyPairGenerator) o;
@@ -180,7 +193,11 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi
}
else if (o instanceof KeyPairGeneratorSpi)
result = new DummyKeyPairGenerator((KeyPairGeneratorSpi) o, algorithm);
-
+ else
+ {
+ sb.append("is of an unexpected Type: ").append(o.getClass().getName());
+ throw new NoSuchAlgorithmException(sb.toString());
+ }
result.provider = provider;
return result;
}
diff --git a/java/security/KeyStore.java b/java/security/KeyStore.java
index e31e8a6c9..1d036c31c 100644
--- a/java/security/KeyStore.java
+++ b/java/security/KeyStore.java
@@ -43,6 +43,7 @@ import gnu.java.security.Engine;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
import java.security.cert.CertificateException;
import java.util.Date;
import java.util.Enumeration;
@@ -108,105 +109,100 @@ public class KeyStore
this.type = type;
}
- // Class methods.
- // ------------------------------------------------------------------------
-
- /**
- * Gets an instance of the KeyStore class representing
- * the specified keystore. If the type is not
- * found then, it throws KeyStoreException.
- *
- * @param type the type of keystore to choose
- * @return a KeyStore repesenting the desired type
- * @throws KeyStoreException if the type of keystore is not implemented
- * by providers or the implementation cannot be instantiated.
+ /**
+ * Returns an instance of a <code>KeyStore</code> representing the specified
+ * type, from the first provider that implements it.
+ *
+ * @param type the type of keystore to create.
+ * @return a <code>KeyStore</code> repesenting the desired type.
+ * @throws KeyStoreException if the designated type of is not implemented by
+ * any provider, or the implementation could not be instantiated.
+ * @throws IllegalArgumentException if <code>type</code> is
+ * <code>null</code> or is an empty string.
*/
public static KeyStore getInstance(String type) throws KeyStoreException
{
Provider[] p = Security.getProviders();
-
+ KeyStoreException lastException = null;
for (int i = 0; i < p.length; i++)
- {
- try
- {
- return getInstance(type, p[i]);
- }
- catch (KeyStoreException e)
- {
- // Ignore.
- }
- }
-
+ try
+ {
+ return getInstance(type, p[i]);
+ }
+ catch (KeyStoreException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new KeyStoreException(type);
}
- /**
- * Gets an instance of the KeyStore class representing
- * the specified key store from the specified provider.
- * If the type is not found then, it throws KeyStoreException.
- * If the provider is not found, then it throws
- * NoSuchProviderException.
- *
- * @param type the type of keystore to choose
- * @param provider the provider name
- * @return a KeyStore repesenting the desired type
- * @throws KeyStoreException if the type of keystore is not
- * implemented by the given provider
- * @throws NoSuchProviderException if the provider is not found
- * @throws IllegalArgumentException if the provider string is
- * null or empty
+ /**
+ * Returns an instance of a <code>KeyStore</code> representing the specified
+ * type, from the named provider.
+ *
+ * @param type the type of keystore to create.
+ * @param provider the name of the provider to use.
+ * @return a <code>KeyStore</code> repesenting the desired type.
+ * @throws KeyStoreException if the designated type is not implemented by the
+ * given provider.
+ * @throws NoSuchProviderException if the provider is not found.
+ * @throws IllegalArgumentException if either <code>type</code> or
+ * <code>provider</code> is <code>null</code> or empty.
*/
public static KeyStore getInstance(String type, String provider)
throws KeyStoreException, NoSuchProviderException
{
- if (provider == null || provider.length() == 0)
- throw new IllegalArgumentException("Illegal provider");
-
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
+ provider = provider.trim();
+ if (provider.length() == 0)
+ throw new IllegalArgumentException("provider MUST NOT be empty");
Provider p = Security.getProvider(provider);
if (p == null)
throw new NoSuchProviderException(provider);
-
return getInstance(type, p);
}
- /**
- * Gets an instance of the KeyStore class representing
- * the specified key store from the specified provider.
- * If the type is not found then, it throws KeyStoreException.
- * If the provider is not found, then it throws
- * NoSuchProviderException.
- *
- * @param type the type of keystore to choose
- * @param provider the keystore provider
- * @return a KeyStore repesenting the desired type
- * @throws KeyStoreException if the type of keystore is not
- * implemented by the given provider
- * @throws IllegalArgumentException if the provider object is null
+ /**
+ * Returns an instance of a <code>KeyStore</code> representing the specified
+ * type, from the specified provider.
+ *
+ * @param type the type of keystore to create.
+ * @param provider the provider to use.
+ * @return a <code>KeyStore</code> repesenting the desired type.
+ * @throws KeyStoreException if the designated type is not implemented by the
+ * given provider.
+ * @throws IllegalArgumentException if either <code>type</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>type</code> is an empty string.
* @since 1.4
*/
public static KeyStore getInstance(String type, Provider provider)
- throws KeyStoreException
+ throws KeyStoreException
{
- if (provider == null)
- throw new IllegalArgumentException("Illegal provider");
+ Throwable cause;
try
{
- return new KeyStore(
- (KeyStoreSpi) Engine.getInstance(KEY_STORE, type, provider),
- provider, type);
+ Object spi = Engine.getInstance(KEY_STORE, type, provider);
+ return new KeyStore((KeyStoreSpi) spi, provider, type);
}
- catch (NoSuchAlgorithmException nsae)
+ catch (NoSuchAlgorithmException x)
{
- throw new KeyStoreException(type);
+ cause = x;
}
- catch (java.lang.reflect.InvocationTargetException ite)
+ catch (InvocationTargetException x)
{
- throw new KeyStoreException(type);
+ cause = x.getCause() != null ? x.getCause() : x;
}
- catch (ClassCastException cce)
+ catch (ClassCastException x)
{
- throw new KeyStoreException(type);
+ cause = x;
}
+ KeyStoreException x = new KeyStoreException(type);
+ x.initCause(cause);
+ throw x;
}
/**
diff --git a/java/security/MessageDigest.java b/java/security/MessageDigest.java
index 8a5de92df..0f8e934e5 100644
--- a/java/security/MessageDigest.java
+++ b/java/security/MessageDigest.java
@@ -40,6 +40,8 @@ package java.security;
import gnu.java.security.Engine;
import java.nio.ByteBuffer;
+import java.lang.reflect.InvocationTargetException;
+
/**
* Message digests are secure one-way hash functions that take arbitrary-sized
* data and output a fixed-length hash value.
@@ -73,28 +75,29 @@ public abstract class MessageDigest extends MessageDigestSpi
* Returns a new instance of <code>MessageDigest</code> representing the
* specified algorithm.
*
- * @param algorithm
- * the name of the digest algorithm to use.
+ * @param algorithm the name of the digest algorithm to use.
* @return a new instance representing the desired algorithm.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by any provider.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by any
+ * provider.
+ * @throws IllegalArgumentException if <code>algorithm</code> is
+ * <code>null</code> or is an empty string.
*/
public static MessageDigest getInstance(String algorithm)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
Provider[] p = Security.getProviders();
+ NoSuchAlgorithmException lastException = null;
for (int i = 0; i < p.length; i++)
- {
- try
- {
- return getInstance(algorithm, p[i]);
- }
- catch (NoSuchAlgorithmException ignored)
- {
- // Ignore.
- }
- }
-
+ try
+ {
+ return getInstance(algorithm, p[i]);
+ }
+ catch (NoSuchAlgorithmException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new NoSuchAlgorithmException(algorithm);
}
@@ -102,29 +105,26 @@ public abstract class MessageDigest extends MessageDigestSpi
* Returns a new instance of <code>MessageDigest</code> representing the
* specified algorithm from a named provider.
*
- * @param algorithm
- * the name of the digest algorithm to use.
- * @param provider
- * the name of the provider to use.
+ * @param algorithm the name of the digest algorithm to use.
+ * @param provider the name of the provider to use.
* @return a new instance representing the desired algorithm.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by the named provider.
- * @throws NoSuchProviderException
- * if the named provider was not found.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by the
+ * named provider.
+ * @throws NoSuchProviderException if the named provider was not found.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code> or empty.
*/
public static MessageDigest getInstance(String algorithm, String provider)
- throws NoSuchAlgorithmException, NoSuchProviderException
+ throws NoSuchAlgorithmException, NoSuchProviderException
{
- if (provider != null)
- provider = provider.trim();
-
- if (provider == null || provider.length() == 0)
- throw new IllegalArgumentException("Illegal provider");
-
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
+ provider = provider.trim();
+ if (provider.length() == 0)
+ throw new IllegalArgumentException("provider MUST NOT be empty");
Provider p = Security.getProvider(provider);
if (p == null)
throw new NoSuchProviderException(provider);
-
return getInstance(algorithm, p);
}
@@ -132,39 +132,43 @@ public abstract class MessageDigest extends MessageDigestSpi
* Returns a new instance of <code>MessageDigest</code> representing the
* specified algorithm from a designated {@link Provider}.
*
- * @param algorithm
- * the name of the digest algorithm to use.
- * @param provider
- * the {@link Provider} to use.
+ * @param algorithm the name of the digest algorithm to use.
+ * @param provider the {@link Provider} to use.
* @return a new instance representing the desired algorithm.
- * @throws IllegalArgumentException
- * if <code>provider</code> is <code>null</code>.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by {@link Provider}.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by
+ * {@link Provider}.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>algorithm</code> is an empty string.
* @since 1.4
* @see Provider
*/
public static MessageDigest getInstance(String algorithm, Provider provider)
throws NoSuchAlgorithmException
{
- if (provider == null)
- throw new IllegalArgumentException("Illegal provider");
-
- MessageDigest result = null;
- Object o = null;
+ StringBuilder sb = new StringBuilder("MessageDigest for algorithm [")
+ .append(algorithm).append("] from provider[")
+ .append(provider).append("] ");
+ Object o;
try
{
o = Engine.getInstance(MESSAGE_DIGEST, algorithm, provider);
}
- catch (java.lang.reflect.InvocationTargetException ite)
+ catch (InvocationTargetException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ Throwable cause = x.getCause();
+ if (cause instanceof NoSuchAlgorithmException)
+ throw (NoSuchAlgorithmException) cause;
+ if (cause == null)
+ cause = x;
+ sb.append("could not be created");
+ NoSuchAlgorithmException y = new NoSuchAlgorithmException(sb.toString());
+ y.initCause(cause);
+ throw y;
}
-
+ MessageDigest result;
if (o instanceof MessageDigestSpi)
- {
- result = new DummyMessageDigest((MessageDigestSpi) o, algorithm);
- }
+ result = new DummyMessageDigest((MessageDigestSpi) o, algorithm);
else if (o instanceof MessageDigest)
{
result = (MessageDigest) o;
@@ -172,7 +176,8 @@ public abstract class MessageDigest extends MessageDigestSpi
}
else
{
- throw new NoSuchAlgorithmException(algorithm);
+ sb.append("is of an unexpected Type: ").append(o.getClass().getName());
+ throw new NoSuchAlgorithmException(sb.toString());
}
result.provider = provider;
return result;
diff --git a/java/security/SecureClassLoader.java b/java/security/SecureClassLoader.java
index bcc3cab88..dfc1758b5 100644
--- a/java/security/SecureClassLoader.java
+++ b/java/security/SecureClassLoader.java
@@ -1,5 +1,5 @@
/* SecureClassLoader.java --- A Secure Class Loader
- Copyright (C) 1999, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,6 +39,9 @@ package java.security;
import java.util.WeakHashMap;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+
/**
* A Secure Class Loader for loading classes with additional
* support for specifying code source and permissions when
@@ -50,22 +53,16 @@ import java.util.WeakHashMap;
*/
public class SecureClassLoader extends ClassLoader
{
- WeakHashMap<CodeSource, ProtectionDomain> protectionDomainCache
- = new WeakHashMap<CodeSource, ProtectionDomain>();
+ private final HashMap<CodeSource,ProtectionDomain> protectionDomainCache
+ = new HashMap<CodeSource, ProtectionDomain>();
protected SecureClassLoader(ClassLoader parent)
{
super(parent);
- SecurityManager sm = System.getSecurityManager();
- if(sm != null)
- sm.checkCreateClassLoader();
}
protected SecureClassLoader()
{
- SecurityManager sm = System.getSecurityManager();
- if(sm != null)
- sm.checkCreateClassLoader();
}
/**
@@ -85,10 +82,35 @@ public class SecureClassLoader extends ClassLoader
protected final Class<?> defineClass(String name, byte[] b, int off, int len,
CodeSource cs)
{
+ return super.defineClass(name, b, off, len, getProtectionDomain(cs));
+ }
+
+ /**
+ * Creates a class using an ByteBuffer and a
+ * CodeSource.
+ *
+ * @param name the name to give the class. null if unknown.
+ * @param b the data representing the classfile, in classfile format.
+ * @param cs the CodeSource for the class or null when unknown.
+ *
+ * @return the class that was defined and optional CodeSource.
+ *
+ * @exception ClassFormatError if the byte array is not in proper classfile format.
+ *
+ * @since 1.5
+ */
+ protected final Class defineClass(String name, ByteBuffer b, CodeSource cs)
+ {
+ return super.defineClass(name, b, getProtectionDomain(cs));
+ }
+
+ /* Lookup or create a protection domain for the CodeSource,
+ * if CodeSource is null it will return null. */
+ private ProtectionDomain getProtectionDomain(CodeSource cs)
+ {
+ ProtectionDomain protectionDomain = null;
if (cs != null)
{
- ProtectionDomain protectionDomain;
-
synchronized (protectionDomainCache)
{
protectionDomain = (ProtectionDomain)protectionDomainCache.get(cs);
@@ -108,10 +130,8 @@ public class SecureClassLoader extends ClassLoader
protectionDomain = domain;
}
}
- return super.defineClass(name, b, off, len, protectionDomain);
- }
- else
- return super.defineClass(name, b, off, len);
+ }
+ return protectionDomain;
}
/**
@@ -120,7 +140,7 @@ public class SecureClassLoader extends ClassLoader
* java.security.Policy.getPermissions.
*
* This method is called by defineClass that takes a CodeSource
- * arguement to build a proper ProtectionDomain for the class
+ * argument to build a proper ProtectionDomain for the class
* being defined.
*/
protected PermissionCollection getPermissions(CodeSource cs)
diff --git a/java/security/SecureRandom.java b/java/security/SecureRandom.java
index c66963e8f..005f4670e 100644
--- a/java/security/SecureRandom.java
+++ b/java/security/SecureRandom.java
@@ -45,6 +45,7 @@ import gnu.java.security.jce.prng.Sha160RandomSpi;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
@@ -187,101 +188,106 @@ public class SecureRandom extends Random
this.algorithm = algorithm;
}
- // Class methods.
- // ------------------------------------------------------------------------
-
/**
- * Returns an instance of a SecureRandom. It creates the class from
- * the first provider that implements it.
- *
+ * Returns an instance of a <code>SecureRandom</code> from the first provider
+ * that implements it.
+ *
* @param algorithm The algorithm name.
- * @return A new SecureRandom implementing the given algorithm.
- * @throws NoSuchAlgorithmException If no installed provider implements
- * the given algorithm.
+ * @return A new <code>SecureRandom</code> implementing the given algorithm.
+ * @throws NoSuchAlgorithmException If no installed provider implements the
+ * given algorithm.
+ * @throws IllegalArgumentException if <code>algorithm</code> is
+ * <code>null</code> or is an empty string.
*/
public static SecureRandom getInstance(String algorithm)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
Provider[] p = Security.getProviders();
-
+ NoSuchAlgorithmException lastException = null;
for (int i = 0; i < p.length; i++)
- {
- try
- {
- return getInstance(algorithm, p[i]);
- }
- catch (NoSuchAlgorithmException e)
- {
- // Ignore.
- }
- }
-
- // None found.
+ try
+ {
+ return getInstance(algorithm, p[i]);
+ }
+ catch (NoSuchAlgorithmException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new NoSuchAlgorithmException(algorithm);
}
/**
- * Returns an instance of a SecureRandom. It creates the class
- * for the specified algorithm from the named provider.
- *
+ * Returns an instance of a <code>SecureRandom</code> for the specified
+ * algorithm from the named provider.
+ *
* @param algorithm The algorithm name.
- * @param provider The provider name.
- * @return A new SecureRandom implementing the chosen algorithm.
+ * @param provider The provider name.
+ * @return A new <code>SecureRandom</code> implementing the chosen
+ * algorithm.
* @throws NoSuchAlgorithmException If the named provider does not implement
- * the algorithm, or if the implementation cannot be
- * instantiated.
- * @throws NoSuchProviderException If no provider named
- * <code>provider</code> is currently installed.
- * @throws IllegalArgumentException If <code>provider</code> is null
- * or is empty.
+ * the algorithm, or if the implementation cannot be instantiated.
+ * @throws NoSuchProviderException If no provider named <code>provider</code>
+ * is currently installed.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code> or empty.
*/
public static SecureRandom getInstance(String algorithm, String provider)
- throws NoSuchAlgorithmException, NoSuchProviderException
+ throws NoSuchAlgorithmException, NoSuchProviderException
{
- if (provider == null || provider.length() == 0)
- throw new IllegalArgumentException("Illegal provider");
-
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
+ provider = provider.trim();
+ if (provider.length() == 0)
+ throw new IllegalArgumentException("provider MUST NOT be empty");
Provider p = Security.getProvider(provider);
if (p == null)
throw new NoSuchProviderException(provider);
-
return getInstance(algorithm, p);
}
/**
- * Returns an instance of a SecureRandom. It creates the class for
- * the specified algorithm from the given provider.
- *
- * @param algorithm The SecureRandom algorithm to create.
- * @param provider The provider to get the instance from.
- * @throws NoSuchAlgorithmException If the algorithm cannot be found, or
- * if the class cannot be instantiated.
- * @throws IllegalArgumentException If <code>provider</code> is null.
+ * Returns an instance of a <code>SecureRandom</code> for the specified
+ * algorithm from the given provider.
+ *
+ * @param algorithm The <code>SecureRandom</code> algorithm to create.
+ * @param provider The provider to use.
+ * @throws NoSuchAlgorithmException If the algorithm cannot be found, or if
+ * the class cannot be instantiated.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>algorithm</code> is an empty string.
*/
public static SecureRandom getInstance(String algorithm, Provider provider)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
- if (provider == null)
- throw new IllegalArgumentException("Illegal provider");
+ StringBuilder sb = new StringBuilder("SecureRandom for algorithm [")
+ .append(algorithm).append("] from provider[")
+ .append(provider).append("] could not be created");
+ Throwable cause;
try
{
- return new SecureRandom((SecureRandomSpi)
- Engine.getInstance(SECURE_RANDOM, algorithm, provider),
- provider, algorithm);
+ Object spi = Engine.getInstance(SECURE_RANDOM, algorithm, provider);
+ return new SecureRandom((SecureRandomSpi) spi, provider, algorithm);
}
- catch (java.lang.reflect.InvocationTargetException ite)
+ catch (InvocationTargetException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ cause = x.getCause();
+ if (cause instanceof NoSuchAlgorithmException)
+ throw (NoSuchAlgorithmException) cause;
+ if (cause == null)
+ cause = x;
}
- catch (ClassCastException cce)
+ catch (ClassCastException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ cause = x;
}
+ NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
+ x.initCause(cause);
+ throw x;
}
- // Instance methods.
- // ------------------------------------------------------------------------
-
/**
Returns the provider being used by the current SecureRandom class.
diff --git a/java/security/Signature.java b/java/security/Signature.java
index 68ae99d42..1245707f7 100644
--- a/java/security/Signature.java
+++ b/java/security/Signature.java
@@ -40,6 +40,7 @@ package java.security;
import gnu.java.security.Engine;
+import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
@@ -128,28 +129,29 @@ public abstract class Signature extends SignatureSpi
* Returns an instance of <code>Signature</code> representing the specified
* signature.
*
- * @param algorithm
- * the algorithm to use.
+ * @param algorithm the algorithm to use.
* @return a new instance repesenting the desired algorithm.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by any provider.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by any
+ * provider.
+ * @throws IllegalArgumentException if <code>algorithm</code> is
+ * <code>null</code> or is an empty string.
*/
public static Signature getInstance(String algorithm)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
Provider[] p = Security.getProviders();
+ NoSuchAlgorithmException lastException = null;
for (int i = 0; i < p.length; i++)
- {
- try
- {
- return getInstance(algorithm, p[i]);
- }
- catch (NoSuchAlgorithmException e)
- {
- // Ignored.
- }
- }
-
+ try
+ {
+ return getInstance(algorithm, p[i]);
+ }
+ catch (NoSuchAlgorithmException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new NoSuchAlgorithmException(algorithm);
}
@@ -157,28 +159,26 @@ public abstract class Signature extends SignatureSpi
* Returns an instance of <code>Signature</code> representing the specified
* signature from the named provider.
*
- * @param algorithm
- * the algorithm to use.
- * @param provider
- * the name of the provider to use.
+ * @param algorithm the algorithm to use.
+ * @param provider the name of the provider to use.
* @return a new instance repesenting the desired algorithm.
- * @throws IllegalArgumentException if <code>provider</code> is
- * <code>null</code> or is an empty string.
- * @throws NoSuchProviderException
- * if the named provider was not found.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by the named provider.
+ * @throws NoSuchProviderException if the named provider was not found.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by the
+ * named provider.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code> or empty.
*/
public static Signature getInstance(String algorithm, String provider)
- throws NoSuchAlgorithmException, NoSuchProviderException
+ throws NoSuchAlgorithmException, NoSuchProviderException
{
- if (provider == null || provider.length() == 0)
- throw new IllegalArgumentException("Illegal provider");
-
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
+ provider = provider.trim();
+ if (provider.length() == 0)
+ throw new IllegalArgumentException("provider MUST NOT be empty");
Provider p = Security.getProvider(provider);
if (p == null)
throw new NoSuchProviderException(provider);
-
return getInstance(algorithm, p);
}
@@ -186,35 +186,41 @@ public abstract class Signature extends SignatureSpi
* Returns an instance of <code>Signature</code> representing the specified
* signature from the specified {@link Provider}.
*
- * @param algorithm
- * the algorithm to use.
- * @param provider
- * the {@link Provider} to use.
+ * @param algorithm the algorithm to use.
+ * @param provider the {@link Provider} to use.
* @return a new instance repesenting the desired algorithm.
- * @throws NoSuchAlgorithmException
- * if the algorithm is not implemented by the {@link Provider}.
+ * @throws NoSuchAlgorithmException if the algorithm is not implemented by the
+ * {@link Provider}.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>algorithm</code> is an empty string.
*/
public static Signature getInstance(String algorithm, Provider provider)
throws NoSuchAlgorithmException
{
- if (provider == null)
- throw new IllegalArgumentException("Illegal provider");
-
- Signature result = null;
- Object o = null;
+ StringBuilder sb = new StringBuilder("Signature algorithm [")
+ .append(algorithm).append("] from provider[")
+ .append(provider).append("] ");
+ Object o;
try
{
o = Engine.getInstance(SIGNATURE, algorithm, provider);
}
- catch (java.lang.reflect.InvocationTargetException ite)
+ catch (InvocationTargetException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ Throwable cause = x.getCause();
+ if (cause instanceof NoSuchAlgorithmException)
+ throw (NoSuchAlgorithmException) cause;
+ if (cause == null)
+ cause = x;
+ sb.append("could not be created");
+ NoSuchAlgorithmException y = new NoSuchAlgorithmException(sb.toString());
+ y.initCause(cause);
+ throw y;
}
-
+ Signature result;
if (o instanceof SignatureSpi)
- {
- result = new DummySignature((SignatureSpi) o, algorithm);
- }
+ result = new DummySignature((SignatureSpi) o, algorithm);
else if (o instanceof Signature)
{
result = (Signature) o;
@@ -222,7 +228,8 @@ public abstract class Signature extends SignatureSpi
}
else
{
- throw new NoSuchAlgorithmException(algorithm);
+ sb.append("is of an unexpected Type: ").append(o.getClass().getName());
+ throw new NoSuchAlgorithmException(sb.toString());
}
result.provider = provider;
return result;
diff --git a/java/security/cert/CertPathBuilder.java b/java/security/cert/CertPathBuilder.java
index f6965205f..519ed2b6c 100644
--- a/java/security/cert/CertPathBuilder.java
+++ b/java/security/cert/CertPathBuilder.java
@@ -40,6 +40,7 @@ package java.security.cert;
import gnu.java.security.Engine;
+import java.lang.reflect.InvocationTargetException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
@@ -111,50 +112,54 @@ public class CertPathBuilder
}
/**
- * Get an instance of a named CertPathBuilder, from the first provider
- * that implements it.
- *
- * @param algorithm The name of the CertPathBuilder to create.
+ * Returns an instance of a named <code>CertPathBuilder</code> from the
+ * first provider that implements it.
+ *
+ * @param algorithm The name of the <code>CertPathBuilder</code> to create.
* @return The new instance.
- * @throws NoSuchAlgorithmException If no installed provider
- * implements the named algorithm.
+ * @throws NoSuchAlgorithmException If no installed provider implements the
+ * named algorithm.
+ * @throws IllegalArgumentException if <code>algorithm</code> is
+ * <code>null</code> or is an empty string.
*/
public static CertPathBuilder getInstance(String algorithm)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
Provider[] p = Security.getProviders();
-
+ NoSuchAlgorithmException lastException = null;
for (int i = 0; i < p.length; i++)
- {
- try
- {
- return getInstance(algorithm, p[i]);
- }
- catch (NoSuchAlgorithmException e)
- {
- // Ignored.
- }
- }
-
+ try
+ {
+ return getInstance(algorithm, p[i]);
+ }
+ catch (NoSuchAlgorithmException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new NoSuchAlgorithmException(algorithm);
}
/**
- * Get an instance of a named CertPathBuilder from the named
+ * Returns an instance of a named <code>CertPathBuilder</code> from a named
* provider.
- *
- * @param algorithm The name of the CertPathBuilder to create.
- * @param provider The name of the provider from which to get the
- * implementation.
+ *
+ * @param algorithm The name of the <code>CertPathBuilder</code> to create.
+ * @param provider The name of the provider to use.
* @return The new instance.
- * @throws NoSuchAlgorithmException If no installed provider
- * implements the named algorithm.
- * @throws NoSuchProviderException If the named provider does not
- * exist.
+ * @throws NoSuchAlgorithmException If no installed provider implements the
+ * named algorithm.
+ * @throws NoSuchProviderException If the named provider does not exist.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>algorithm</code> is an empty string.
*/
public static CertPathBuilder getInstance(String algorithm, String provider)
- throws NoSuchAlgorithmException, NoSuchProviderException
+ throws NoSuchAlgorithmException, NoSuchProviderException
{
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
Provider p = Security.getProvider(provider);
if (p == null)
throw new NoSuchProviderException(provider);
@@ -162,41 +167,47 @@ public class CertPathBuilder
}
/**
- * Get an instance of a named CertPathBuilder from the specified
- * provider.
- *
- * @param algorithm The name of the CertPathBuilder to create.
- * @param provider The provider from which to get the implementation.
+ * Returns an instance of a named <code>CertPathBuilder</code> from the
+ * specified provider.
+ *
+ * @param algorithm The name of the <code>CertPathBuilder</code> to create.
+ * @param provider The provider to use.
* @return The new instance.
- * @throws NoSuchAlgorithmException If no installed provider
- * implements the named algorithm.
- * @throws IllegalArgumentException If <i>provider</i> in
- * <tt>null</tt>.
+ * @throws NoSuchAlgorithmException If no installed provider implements the
+ * named algorithm.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>algorithm</code> is an empty string.
*/
public static CertPathBuilder getInstance(String algorithm, Provider provider)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
- if (provider == null)
- throw new IllegalArgumentException("null provider");
+ StringBuilder sb = new StringBuilder("CertPathBuilder for algorithm [")
+ .append(algorithm).append("] from provider[")
+ .append(provider).append("] could not be created");
+ Throwable cause;
try
{
- return new CertPathBuilder((CertPathBuilderSpi)
- Engine.getInstance(CERT_PATH_BUILDER, algorithm, provider),
- provider, algorithm);
+ Object spi = Engine.getInstance(CERT_PATH_BUILDER, algorithm, provider);
+ return new CertPathBuilder((CertPathBuilderSpi) spi, provider, algorithm);
}
- catch (java.lang.reflect.InvocationTargetException ite)
+ catch (InvocationTargetException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ cause = x.getCause();
+ if (cause instanceof NoSuchAlgorithmException)
+ throw (NoSuchAlgorithmException) cause;
+ if (cause == null)
+ cause = x;
}
- catch (ClassCastException cce)
+ catch (ClassCastException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ cause = x;
}
+ NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
+ x.initCause(cause);
+ throw x;
}
- // Instance methods.
- // ------------------------------------------------------------------------
-
/**
* Return the name of this CertPathBuilder algorithm.
*
diff --git a/java/security/cert/CertPathValidator.java b/java/security/cert/CertPathValidator.java
index 5fed19e9a..bf7c9746e 100644
--- a/java/security/cert/CertPathValidator.java
+++ b/java/security/cert/CertPathValidator.java
@@ -40,6 +40,7 @@ package java.security.cert;
import gnu.java.security.Engine;
+import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
@@ -124,91 +125,103 @@ public class CertPathValidator {
}
/**
- * Get an instance of the given validator from the first provider that
+ * Returns an instance of the given validator from the first provider that
* implements it.
- *
+ *
* @param algorithm The name of the algorithm to get.
* @return The new instance.
- * @throws NoSuchAlgorithmException If no installed provider
- * implements the requested algorithm.
+ * @throws NoSuchAlgorithmException If no installed provider implements the
+ * requested algorithm.
+ * @throws IllegalArgumentException if <code>algorithm</code> is
+ * <code>null</code> or is an empty string.
*/
public static CertPathValidator getInstance(String algorithm)
throws NoSuchAlgorithmException
{
Provider[] p = Security.getProviders();
+ NoSuchAlgorithmException lastException = null;
for (int i = 0; i < p.length; i++)
- {
- try
- {
- return getInstance(algorithm, p[i]);
- }
- catch (NoSuchAlgorithmException e)
- {
- // Ignored.
- }
- }
+ try
+ {
+ return getInstance(algorithm, p[i]);
+ }
+ catch (NoSuchAlgorithmException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new NoSuchAlgorithmException(algorithm);
}
/**
- * Get an instance of the given validator from the named provider.
- *
+ * Returns an instance of the given validator from the named provider.
+ *
* @param algorithm The name of the algorithm to get.
- * @param provider The name of the provider from which to get the
- * implementation.
+ * @param provider The name of the provider from which to get the
+ * implementation.
* @return The new instance.
- * @throws NoSuchAlgorithmException If the named provider does not
- * implement the algorithm.
- * @throws NoSuchProviderException If no provider named
- * <i>provider</i> is installed.
+ * @throws NoSuchAlgorithmException If the named provider does not implement
+ * the algorithm.
+ * @throws NoSuchProviderException If no provider named <i>provider</i> is
+ * installed.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>algorithm</code> is an empty string.
*/
- public static CertPathValidator getInstance(String algorithm,
- String provider)
- throws NoSuchAlgorithmException, NoSuchProviderException
+ public static CertPathValidator getInstance(String algorithm, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException
{
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
Provider p = Security.getProvider(provider);
if (p == null)
throw new NoSuchProviderException(provider);
-
return getInstance(algorithm, p);
}
/**
- * Get an instance of the given validator from the given provider.
- *
+ * Returns an instance of the given validator from the given provider.
+ *
* @param algorithm The name of the algorithm to get.
- * @param provider The provider from which to get the implementation.
+ * @param provider The provider from which to get the implementation.
* @return The new instance.
- * @throws NoSuchAlgorithmException If the provider does not implement
- * the algorithm.
- * @throws IllegalArgumentException If <i>provider</i> is null.
+ * @throws NoSuchAlgorithmException If the provider does not implement the
+ * algorithm.
+ * @throws IllegalArgumentException if either <code>algorithm</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>algorithm</code> is an empty string.
*/
public static CertPathValidator getInstance(String algorithm,
Provider provider)
throws NoSuchAlgorithmException
{
- if (provider == null)
- throw new IllegalArgumentException("null provider");
-
+ StringBuilder sb = new StringBuilder("CertPathValidator for algorithm [")
+ .append(algorithm).append("] from provider[")
+ .append(provider).append("] could not be created");
+ Throwable cause;
try
{
- return new CertPathValidator((CertPathValidatorSpi)
- Engine.getInstance(CERT_PATH_VALIDATOR, algorithm, provider),
- provider, algorithm);
+ Object spi = Engine.getInstance(CERT_PATH_VALIDATOR, algorithm, provider);
+ return new CertPathValidator((CertPathValidatorSpi) spi, provider, algorithm);
}
- catch (java.lang.reflect.InvocationTargetException ite)
+ catch (InvocationTargetException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ cause = x.getCause();
+ if (cause instanceof NoSuchAlgorithmException)
+ throw (NoSuchAlgorithmException) cause;
+ if (cause == null)
+ cause = x;
}
- catch (ClassCastException cce)
+ catch (ClassCastException x)
{
- throw new NoSuchAlgorithmException(algorithm);
+ cause = x;
}
+ NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
+ x.initCause(cause);
+ throw x;
}
- // Instance methods.
- // ------------------------------------------------------------------------
-
/**
* Return the name of this validator.
*
diff --git a/java/security/cert/CertStore.java b/java/security/cert/CertStore.java
index 2d5d944db..a27086562 100644
--- a/java/security/cert/CertStore.java
+++ b/java/security/cert/CertStore.java
@@ -40,6 +40,7 @@ package java.security.cert;
import gnu.java.security.Engine;
+import java.lang.reflect.InvocationTargetException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
@@ -123,59 +124,63 @@ public class CertStore
}
/**
- * Get an instance of the given certificate store from the first
+ * Returns an instance of the given certificate store type from the first
* installed provider.
- *
- * @param type The type of CertStore to create.
- * @param params The parameters to initialize this cert store with.
+ *
+ * @param type The type of <code>CertStore</code> to create.
+ * @param params The parameters to initialize this cert store with.
* @return The new instance.
- * @throws InvalidAlgorithmParameterException If the instance rejects
- * the specified parameters.
- * @throws NoSuchAlgorithmException If no installed provider
- * implements the specified CertStore.
- * @throws IllegalArgumentException If <i>provider</i> is null.
+ * @throws InvalidAlgorithmParameterException If the instance rejects the
+ * specified parameters.
+ * @throws NoSuchAlgorithmException If no installed provider implements the
+ * specified CertStore.
+ * @throws IllegalArgumentException if <code>type</code> is
+ * <code>null</code> or is an empty string.
*/
public static CertStore getInstance(String type, CertStoreParameters params)
throws InvalidAlgorithmParameterException, NoSuchAlgorithmException
{
Provider[] p = Security.getProviders();
+ NoSuchAlgorithmException lastException = null;
for (int i = 0; i < p.length; i++)
- {
- try
- {
- return getInstance(type, params, p[i]);
- }
- catch (NoSuchAlgorithmException e)
- {
- // Ignored.
- }
- }
-
+ try
+ {
+ return getInstance(type, params, p[i]);
+ }
+ catch (NoSuchAlgorithmException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new NoSuchAlgorithmException(type);
}
/**
- * Get an instance of the given certificate store from the named
+ * Returns an instance of the given certificate store type from a named
* provider.
- *
- * @param type The type of CertStore to create.
- * @param params The parameters to initialize this cert store with.
- * @param provider The name of the provider from which to get the
- * implementation.
+ *
+ * @param type The type of <code>CertStore</code> to create.
+ * @param params The parameters to initialize this cert store with.
+ * @param provider The name of the provider to use.
* @return The new instance.
- * @throws InvalidAlgorithmParameterException If the instance rejects
- * the specified parameters.
+ * @throws InvalidAlgorithmParameterException If the instance rejects the
+ * specified parameters.
* @throws NoSuchAlgorithmException If the specified provider does not
- * implement the specified CertStore.
- * @throws NoSuchProviderException If no provider named
- * <i>provider</i> is installed.
- * @throws IllegalArgumentException If <i>provider</i> is null.
+ * implement the specified CertStore.
+ * @throws NoSuchProviderException If no provider named <i>provider</i> is
+ * installed.
+ * @throws IllegalArgumentException if either <code>type</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>type</code> is an empty string.
*/
public static CertStore getInstance(String type, CertStoreParameters params,
String provider)
throws InvalidAlgorithmParameterException, NoSuchAlgorithmException,
NoSuchProviderException
{
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
Provider p = Security.getProvider(provider);
if (p == null)
throw new NoSuchProviderException(provider);
@@ -183,48 +188,52 @@ public class CertStore
}
/**
- * Get an instance of the given certificate store from the given
+ * Returns an instance of the given certificate store type from a given
* provider.
*
- * @param type The type of CertStore to create.
+ * @param type The type of <code>CertStore</code> to create.
* @param params The parameters to initialize this cert store with.
- * @param provider The provider from which to get the implementation.
+ * @param provider The provider to use.
* @return The new instance.
* @throws InvalidAlgorithmParameterException If the instance rejects
* the specified parameters.
* @throws NoSuchAlgorithmException If the specified provider does not
* implement the specified CertStore.
- * @throws IllegalArgumentException If <i>provider</i> is null.
+ * @throws IllegalArgumentException if either <code>type</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>type</code> is an empty string.
*/
public static CertStore getInstance(String type, CertStoreParameters params,
Provider provider)
- throws InvalidAlgorithmParameterException, NoSuchAlgorithmException
+ throws InvalidAlgorithmParameterException, NoSuchAlgorithmException
{
- if (provider == null)
- throw new IllegalArgumentException("null provider");
-
+ StringBuilder sb = new StringBuilder("CertStore of type [")
+ .append(type).append("] from provider[")
+ .append(provider).append("] could not be created");
+ Throwable cause;
try
{
- return new CertStore((CertStoreSpi) Engine.getInstance(CERT_STORE,
- type, provider, new Object[] { params }), provider, type, params);
+ Object[] args = new Object[] { params };
+ Object spi = Engine.getInstance(CERT_STORE, type, provider, args);
+ return new CertStore((CertStoreSpi) spi, provider, type, params);
}
- catch (ClassCastException cce)
+ catch (InvocationTargetException x)
{
- throw new NoSuchAlgorithmException(type);
+ cause = x.getCause();
+ if (cause instanceof NoSuchAlgorithmException)
+ throw (NoSuchAlgorithmException) cause;
+ if (cause == null)
+ cause = x;
}
- catch (java.lang.reflect.InvocationTargetException ite)
+ catch (ClassCastException x)
{
- Throwable cause = ite.getCause();
- if (cause instanceof InvalidAlgorithmParameterException)
- throw (InvalidAlgorithmParameterException) cause;
- else
- throw new NoSuchAlgorithmException(type);
+ cause = x;
}
+ NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
+ x.initCause(cause);
+ throw x;
}
- // Instance methods.
- // ------------------------------------------------------------------------
-
/**
* Return the type of certificate store this instance represents.
*
diff --git a/java/security/cert/CertificateFactory.java b/java/security/cert/CertificateFactory.java
index 363c750cc..8139c6ec5 100644
--- a/java/security/cert/CertificateFactory.java
+++ b/java/security/cert/CertificateFactory.java
@@ -41,6 +41,8 @@ package java.security.cert;
import gnu.java.security.Engine;
import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Provider;
@@ -84,106 +86,102 @@ public class CertificateFactory
this.type = type;
}
- // Class methods.
- // ------------------------------------------------------------------------
-
- /**
- * Gets an instance of the CertificateFactory class representing
- * the specified certificate factory. If the type is not
- * found then, it throws CertificateException.
- *
- * @param type The type of certificate factory to create.
- * @return a CertificateFactory repesenting the desired type
- * @throws CertificateException If the type of certificate is not
- * implemented by any installed provider.
+ /**
+ * Returns an instance of a <code>CertificateFactory</code> representing the
+ * specified certificate factory type.
+ *
+ * @param type The type of certificate factory to create.
+ * @return A <code>CertificateFactory</code> of the desired type.
+ * @throws CertificateException If the type of certificate factory is not
+ * implemented by any installed provider.
+ * @throws IllegalArgumentException if <code>type</code> is
+ * <code>null</code> or is an empty string.
*/
public static final CertificateFactory getInstance(String type)
- throws CertificateException
+ throws CertificateException
{
Provider[] p = Security.getProviders();
-
+ CertificateException lastException = null;
for (int i = 0; i < p.length; i++)
- {
- try
- {
- return getInstance(type, p[i]);
- }
- catch (CertificateException e)
- {
- // Ignored.
- }
- }
-
+ try
+ {
+ return getInstance(type, p[i]);
+ }
+ catch (CertificateException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new CertificateException(type);
}
- /**
- * Gets an instance of the CertificateFactory class representing
- * the specified certificate factory from the specified provider.
- * If the type is not found then, it throws {@link CertificateException}.
- * If the provider is not found, then it throws
- * {@link java.security.NoSuchProviderException}.
- *
- * @param type The type of certificate factory to create.
- * @param provider The name of the provider from which to get the
- * implementation.
- * @return A CertificateFactory for the desired type.
- * @throws CertificateException If the type of certificate is not
- * implemented by the named provider.
+ /**
+ * Returns an instance of a <code>CertificateFactory</code> representing the
+ * specified certificate factory type from the named provider.
+ *
+ * @param type The type of certificate factory to create.
+ * @param provider The name of the provider to use.
+ * @return A <code>CertificateFactory</code> for the desired type.
+ * @throws CertificateException If the type of certificate is not implemented
+ * by the named provider.
* @throws NoSuchProviderException If the named provider is not installed.
+ * @throws IllegalArgumentException if either <code>type</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>type</code> is an empty string.
*/
public static final CertificateFactory getInstance(String type,
String provider)
throws CertificateException, NoSuchProviderException
{
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
Provider p = Security.getProvider(provider);
- if( p == null)
+ if (p == null)
throw new NoSuchProviderException(provider);
-
return getInstance(type, p);
}
/**
- * Get a certificate factory for the given certificate type from the
- * given provider.
- *
- * @param type The type of certificate factory to create.
+ * Returns an instance of a <code>CertificateFactory</code> representing the
+ * specified certificate factory type from the designated provider.
+ *
+ * @param type The type of certificate factory to create.
* @param provider The provider from which to get the implementation.
- * @return A CertificateFactory for the desired type.
- * @throws CertificateException If the type of certificate is not
- * implemented by the provider.
- * @throws IllegalArgumentException If the provider is null.
+ * @return A <code>CertificateFactory</code> for the desired type.
+ * @throws CertificateException If the type of certificate is not implemented
+ * by the provider.
+ * @throws IllegalArgumentException if either <code>type</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>type</code> is an empty string.
*/
public static final CertificateFactory getInstance(String type,
Provider provider)
- throws CertificateException
+ throws CertificateException
{
- if (provider == null)
- throw new IllegalArgumentException("null provider");
-
+ Throwable cause;
try
{
- return new CertificateFactory((CertificateFactorySpi)
- Engine.getInstance(CERTIFICATE_FACTORY, type, provider),
- provider, type);
+ Object spi = Engine.getInstance(CERTIFICATE_FACTORY, type, provider);
+ return new CertificateFactory((CertificateFactorySpi) spi, provider, type);
}
- catch (ClassCastException cce)
+ catch (ClassCastException x)
{
- throw new CertificateException(type);
+ cause = x;
}
- catch (java.lang.reflect.InvocationTargetException ite)
+ catch (InvocationTargetException x)
{
- throw new CertificateException(type);
+ cause = x.getCause() != null ? x.getCause() : x;
}
- catch (NoSuchAlgorithmException nsae)
+ catch (NoSuchAlgorithmException x)
{
- throw new CertificateException(nsae.getMessage());
+ cause = x;
}
+ CertificateException x = new CertificateException(type);
+ x.initCause(cause);
+ throw x;
}
- // Instance methods.
- // ------------------------------------------------------------------------
-
/**
* Gets the provider of this implementation.
*
diff --git a/java/util/Calendar.java b/java/util/Calendar.java
index 6865230c8..8c46c0193 100644
--- a/java/util/Calendar.java
+++ b/java/util/Calendar.java
@@ -1,5 +1,6 @@
/* Calendar.java --
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006,
+ Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -484,6 +485,8 @@ public abstract class Calendar
/**
* Creates a calendar representing the actual time, using the default
* time zone and locale.
+ *
+ * @return The new calendar.
*/
public static synchronized Calendar getInstance()
{
@@ -493,7 +496,12 @@ public abstract class Calendar
/**
* Creates a calendar representing the actual time, using the given
* time zone and the default locale.
- * @param zone a time zone.
+ *
+ * @param zone a time zone (<code>null</code> not permitted).
+ *
+ * @return The new calendar.
+ *
+ * @throws NullPointerException if <code>zone</code> is <code>null</code>.
*/
public static synchronized Calendar getInstance(TimeZone zone)
{
@@ -503,7 +511,12 @@ public abstract class Calendar
/**
* Creates a calendar representing the actual time, using the default
* time zone and the given locale.
- * @param locale a locale.
+ *
+ * @param locale a locale (<code>null</code> not permitted).
+ *
+ * @return The new calendar.
+ *
+ * @throws NullPointerException if <code>locale</code> is <code>null</code>.
*/
public static synchronized Calendar getInstance(Locale locale)
{
@@ -525,8 +538,14 @@ public abstract class Calendar
/**
* Creates a calendar representing the actual time, using the given
* time zone and locale.
- * @param zone a time zone.
- * @param locale a locale.
+ *
+ * @param zone a time zone (<code>null</code> not permitted).
+ * @param locale a locale (<code>null</code> not permitted).
+ *
+ * @return The new calendar.
+ *
+ * @throws NullPointerException if <code>zone</code> or <code>locale</code>
+ * is <code>null</code>.
*/
public static synchronized Calendar getInstance(TimeZone zone, Locale locale)
{
@@ -618,6 +637,10 @@ public abstract class Calendar
/**
* Sets this Calendar's time to the given Date. All time fields
* are invalidated by this method.
+ *
+ * @param date the date (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if <code>date</code> is <code>null</code>.
*/
public final void setTime(Date date)
{
diff --git a/java/util/Locale.java b/java/util/Locale.java
index d2aead43c..001c7afde 100644
--- a/java/util/Locale.java
+++ b/java/util/Locale.java
@@ -188,11 +188,17 @@ public final class Locale implements Serializable, Cloneable
private String variant;
/**
- * This is the cached hashcode. When writing to stream, we write -1.
+ * This is where the JDK caches its hashcode. This is is only here
+ * for serialization purposes. The actual cache is hashcodeCache
*
* @serial should be -1 in serial streams
*/
- private transient int hashcode;
+ private int hashcode = -1;
+
+ /**
+ * This is the cached hashcode.
+ */
+ private transient int hashcodeCache;
/**
* Array storing all available locales.
@@ -324,7 +330,7 @@ public final class Locale implements Serializable, Cloneable
this.language = language;
this.country = country;
this.variant = variant;
- hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
+ hashcodeCache = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
}
/**
@@ -899,7 +905,7 @@ public final class Locale implements Serializable, Cloneable
*/
public int hashCode()
{
- return hashcode;
+ return hashcodeCache;
}
/**
@@ -917,32 +923,12 @@ public final class Locale implements Serializable, Cloneable
return false;
Locale l = (Locale) obj;
- return (language == l.language
- && country == l.country
+ return (language == l.language
+ && country == l.country
&& variant == l.variant);
}
/**
- * Write the locale to an object stream.
- *
- * @param s the stream to write to
- * @throws IOException if the write fails
- * @serialData The first three fields are Strings representing language,
- * country, and variant. The fourth field is a placeholder for
- * the cached hashcode, but this is always written as -1, and
- * recomputed when reading it back.
- */
- private void writeObject(ObjectOutputStream s)
- throws IOException
- {
- s.writeObject(language);
- s.writeObject(country);
- s.writeObject(variant);
- // Hashcode field is always written as -1.
- s.writeInt(-1);
- }
-
- /**
* Reads a locale from the input stream.
*
* @param s the stream to read from
@@ -953,10 +939,10 @@ public final class Locale implements Serializable, Cloneable
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
- language = ((String) s.readObject()).intern();
- country = ((String) s.readObject()).intern();
- variant = ((String) s.readObject()).intern();
- // Recompute hashcode.
- hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
+ s.defaultReadObject();
+ language = language.intern();
+ country = country.intern();
+ variant = variant.intern();
+ hashcodeCache = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
}
} // class Locale
diff --git a/java/util/ResourceBundle.java b/java/util/ResourceBundle.java
index 751d380b2..9b82bc801 100644
--- a/java/util/ResourceBundle.java
+++ b/java/util/ResourceBundle.java
@@ -91,6 +91,14 @@ baseName</pre>
public abstract class ResourceBundle
{
/**
+ * Maximum size of our cache of <code>ResourceBundle</code>s keyed by
+ * {@link BundleKey} instances.
+ *
+ * @see BundleKey
+ */
+ private static final int CACHE_SIZE = 100;
+
+ /**
* The parent bundle. This is consulted when you call getObject and there
* is no such resource in the current bundle. This field may be null.
*/
@@ -104,21 +112,22 @@ public abstract class ResourceBundle
private Locale locale;
/**
- * The resource bundle cache.
- */
- private static Map bundleCache;
-
- /**
- * The last default Locale we saw. If this ever changes then we have to
- * reset our caches.
- */
- private static Locale lastDefaultLocale;
-
- /**
- * The `empty' locale is created once in order to optimize
- * tryBundle().
+ * A VM-wide cache of resource bundles already fetched.
+ * <p>
+ * This {@link Map} is a Least Recently Used (LRU) cache, of the last
+ * {@link #CACHE_SIZE} accessed <code>ResourceBundle</code>s keyed by the
+ * tuple: default locale, resource-bundle name, resource-bundle locale, and
+ * classloader.
+ *
+ * @see BundleKey
*/
- private static final Locale emptyLocale = new Locale("");
+ private static Map bundleCache = new LinkedHashMap(CACHE_SIZE + 1, 0.75F, true)
+ {
+ public boolean removeEldestEntry(Map.Entry entry)
+ {
+ return size() > CACHE_SIZE;
+ }
+ };
/**
* The constructor. It does nothing special.
@@ -246,6 +255,7 @@ public abstract class ResourceBundle
by the combination of bundle name, locale, and class loader. */
private static class BundleKey
{
+ Locale defaultLocale;
String baseName;
Locale locale;
ClassLoader classLoader;
@@ -253,18 +263,19 @@ public abstract class ResourceBundle
BundleKey() {}
- BundleKey(String s, Locale l, ClassLoader cl)
+ BundleKey(Locale dl, String s, Locale l, ClassLoader cl)
{
- set(s, l, cl);
+ set(dl, s, l, cl);
}
- void set(String s, Locale l, ClassLoader cl)
+ void set(Locale dl, String s, Locale l, ClassLoader cl)
{
+ defaultLocale = dl;
baseName = s;
locale = l;
classLoader = cl;
- hashcode = baseName.hashCode() ^ locale.hashCode() ^
- classLoader.hashCode();
+ hashcode = defaultLocale.hashCode() ^ baseName.hashCode()
+ ^ locale.hashCode() ^ classLoader.hashCode();
}
public int hashCode()
@@ -277,10 +288,11 @@ public abstract class ResourceBundle
if (! (o instanceof BundleKey))
return false;
BundleKey key = (BundleKey) o;
- return hashcode == key.hashcode &&
- baseName.equals(key.baseName) &&
- locale.equals(key.locale) &&
- classLoader.equals(key.classLoader);
+ return hashcode == key.hashcode
+ && defaultLocale.equals(key.defaultLocale)
+ && baseName.equals(key.baseName)
+ && locale.equals(key.locale)
+ && classLoader.equals(key.classLoader);
}
}
@@ -370,61 +382,39 @@ public abstract class ResourceBundle
public static synchronized ResourceBundle getBundle
(String baseName, Locale locale, ClassLoader classLoader)
{
- // If the default locale changed since the last time we were called,
- // all cache entries are invalidated.
Locale defaultLocale = Locale.getDefault();
- if (defaultLocale != lastDefaultLocale)
- {
- bundleCache = new HashMap();
- lastDefaultLocale = defaultLocale;
- }
-
// This will throw NullPointerException if any arguments are null.
- lookupKey.set(baseName, locale, classLoader);
-
+ lookupKey.set(defaultLocale, baseName, locale, classLoader);
Object obj = bundleCache.get(lookupKey);
- ResourceBundle rb = null;
-
if (obj instanceof ResourceBundle)
+ return (ResourceBundle) obj;
+
+ if (obj == nullEntry)
+ throw new MissingResourceException("Bundle " + baseName
+ + " not found for locale " + locale
+ + " by classloader " + classLoader,
+ baseName, "");
+ // First, look for a bundle for the specified locale. We don't want
+ // the base bundle this time.
+ boolean wantBase = locale.equals(defaultLocale);
+ ResourceBundle bundle = tryBundle(baseName, locale, classLoader, wantBase);
+ // Try the default locale if neccessary.
+ if (bundle == null && ! wantBase)
+ bundle = tryBundle(baseName, defaultLocale, classLoader, true);
+
+ BundleKey key = new BundleKey(defaultLocale, baseName, locale, classLoader);
+ if (bundle == null)
{
- return (ResourceBundle) obj;
- }
- else if (obj == nullEntry)
- {
- // Lookup has failed previously. Fall through.
+ // Cache the fact that this lookup has previously failed.
+ bundleCache.put(key, nullEntry);
+ throw new MissingResourceException("Bundle " + baseName
+ + " not found for locale " + locale
+ + " by classloader " + classLoader,
+ baseName, "");
}
- else
- {
- // First, look for a bundle for the specified locale. We don't want
- // the base bundle this time.
- boolean wantBase = locale.equals(defaultLocale);
- ResourceBundle bundle = tryBundle(baseName, locale, classLoader,
- wantBase);
-
- // Try the default locale if neccessary.
- if (bundle == null && !locale.equals(defaultLocale))
- bundle = tryBundle(baseName, defaultLocale, classLoader, true);
-
- BundleKey key = new BundleKey(baseName, locale, classLoader);
- if (bundle == null)
- {
- // Cache the fact that this lookup has previously failed.
- bundleCache.put(key, nullEntry);
- }
- else
- {
- // Cache the result and return it.
- bundleCache.put(key, bundle);
- return bundle;
- }
- }
-
- throw new MissingResourceException("Bundle " + baseName
- + " not found for locale "
- + locale
- + " by classloader "
- + classLoader,
- baseName, "");
+ // Cache the result and return it.
+ bundleCache.put(key, bundle);
+ return bundle;
}
/**
diff --git a/java/util/Vector.java b/java/util/Vector.java
index 02eb1539a..ea29ce093 100644
--- a/java/util/Vector.java
+++ b/java/util/Vector.java
@@ -720,8 +720,10 @@ public class Vector<T> extends AbstractList<T>
*/
public synchronized boolean removeAll(Collection<?> c)
{
- if (c == null)
- throw new NullPointerException();
+ // The NullPointerException is thrown implicitly when the Vector
+ // is not empty and c is null. The RI allows null arguments when
+ // the vector is empty. See Mauve test:
+ // gnu/testlet/java/util/Vector/removeAll.java
int i;
int j;
@@ -749,8 +751,10 @@ public class Vector<T> extends AbstractList<T>
*/
public synchronized boolean retainAll(Collection<?> c)
{
- if (c == null)
- throw new NullPointerException();
+ // The NullPointerException is thrown implicitly when the Vector
+ // is not empty and c is null. The RI allows null arguments when
+ // the vector is empty. See Mauve test:
+ // gnu/testlet/java/util/Vector/retainAll.java
int i;
int j;
diff --git a/java/util/regex/Matcher.java b/java/util/regex/Matcher.java
index 25e73810e..3ddd42547 100644
--- a/java/util/regex/Matcher.java
+++ b/java/util/regex/Matcher.java
@@ -218,7 +218,7 @@ public final class Matcher implements MatchResult
public boolean lookingAt ()
{
- match = pattern.getRE().getMatch(inputCharIndexed, 0);
+ match = pattern.getRE().getMatch(inputCharIndexed, 0, RE.REG_FIX_STARTING_POSITION, null);
if (match != null)
{
if (match.getStartIndex() == 0)
@@ -243,7 +243,7 @@ public final class Matcher implements MatchResult
*/
public boolean matches ()
{
- match = pattern.getRE().getMatch(inputCharIndexed, 0, RE.REG_TRY_ENTIRE_MATCH);
+ match = pattern.getRE().getMatch(inputCharIndexed, 0, RE.REG_TRY_ENTIRE_MATCH|RE.REG_FIX_STARTING_POSITION, null);
if (match != null)
{
if (match.getStartIndex() == 0)
@@ -309,6 +309,28 @@ public final class Matcher implements MatchResult
return match.getStartIndex(group);
}
+ /**
+ * @return True if and only if the matcher hit the end of input.
+ */
+ public boolean hitEnd()
+ {
+ return inputCharIndexed.hitEnd();
+ }
+
+ /**
+ * @return A string expression of this matcher.
+ */
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getClass().getName())
+ .append("[pattern=").append(pattern.pattern())
+ .append(" region=").append("0").append(",").append(input.length())
+ .append(" lastmatch=").append(match == null ? "" : match.toString())
+ .append("]");
+ return sb.toString();
+ }
+
private void assertMatchOp()
{
if (match == null) throw new IllegalStateException();
diff --git a/java/util/zip/ZipFile.java b/java/util/zip/ZipFile.java
index 00ba19b15..3b34bd1f5 100644
--- a/java/util/zip/ZipFile.java
+++ b/java/util/zip/ZipFile.java
@@ -48,6 +48,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -516,6 +519,16 @@ public class ZipFile implements ZipConstants
private static final class PartialInputStream extends InputStream
{
+ /**
+ * The UTF-8 charset use for decoding the filenames.
+ */
+ private static final Charset UTF8CHARSET = Charset.forName("UTF-8");
+
+ /**
+ * The actual UTF-8 decoder. Created on demand.
+ */
+ private CharsetDecoder utf8Decoder;
+
private final RandomAccessFile raf;
private final byte[] buffer;
private long bufferOffset;
@@ -652,23 +665,86 @@ public class ZipFile implements ZipConstants
int readLeShort() throws IOException
{
- int b0 = read();
- int b1 = read();
- if (b1 == -1)
- throw new EOFException();
- return (b0 & 0xff) | (b1 & 0xff) << 8;
+ int result;
+ if(pos + 1 < buffer.length)
+ {
+ result = ((buffer[pos + 0] & 0xff) | (buffer[pos + 1] & 0xff) << 8);
+ pos += 2;
+ }
+ else
+ {
+ int b0 = read();
+ int b1 = read();
+ if (b1 == -1)
+ throw new EOFException();
+ result = (b0 & 0xff) | (b1 & 0xff) << 8;
+ }
+ return result;
}
int readLeInt() throws IOException
{
- int b0 = read();
- int b1 = read();
- int b2 = read();
- int b3 = read();
- if (b3 == -1)
- throw new EOFException();
- return ((b0 & 0xff) | (b1 & 0xff) << 8)
- | ((b2 & 0xff) | (b3 & 0xff) << 8) << 16;
+ int result;
+ if(pos + 3 < buffer.length)
+ {
+ result = (((buffer[pos + 0] & 0xff) | (buffer[pos + 1] & 0xff) << 8)
+ | ((buffer[pos + 2] & 0xff)
+ | (buffer[pos + 3] & 0xff) << 8) << 16);
+ pos += 4;
+ }
+ else
+ {
+ int b0 = read();
+ int b1 = read();
+ int b2 = read();
+ int b3 = read();
+ if (b3 == -1)
+ throw new EOFException();
+ result = (((b0 & 0xff) | (b1 & 0xff) << 8) | ((b2 & 0xff)
+ | (b3 & 0xff) << 8) << 16);
+ }
+ return result;
+ }
+
+ /**
+ * Decode chars from byte buffer using UTF8 encoding. This
+ * operation is performance-critical since a jar file contains a
+ * large number of strings for the name of each file in the
+ * archive. This routine therefore avoids using the expensive
+ * utf8Decoder when decoding is straightforward.
+ *
+ * @param buffer the buffer that contains the encoded character
+ * data
+ * @param pos the index in buffer of the first byte of the encoded
+ * data
+ * @param length the length of the encoded data in number of
+ * bytes.
+ *
+ * @return a String that contains the decoded characters.
+ */
+ private String decodeChars(byte[] buffer, int pos, int length)
+ throws IOException
+ {
+ String result;
+ int i=length - 1;
+ while ((i >= 0) && (buffer[i] <= 0x7f))
+ {
+ i--;
+ }
+ if (i < 0)
+ {
+ result = new String(buffer, 0, pos, length);
+ }
+ else
+ {
+ ByteBuffer bufferBuffer = ByteBuffer.wrap(buffer, pos, length);
+ if (utf8Decoder == null)
+ utf8Decoder = UTF8CHARSET.newDecoder();
+ utf8Decoder.reset();
+ char [] characters = utf8Decoder.decode(bufferBuffer).array();
+ result = String.valueOf(characters);
+ }
+ return result;
}
String readString(int length) throws IOException
@@ -676,25 +752,26 @@ public class ZipFile implements ZipConstants
if (length > end - (bufferOffset + pos))
throw new EOFException();
+ String result = null;
try
{
if (buffer.length - pos >= length)
{
- String s = new String(buffer, pos, length, "UTF-8");
+ result = decodeChars(buffer, pos, length);
pos += length;
- return s;
}
else
{
byte[] b = new byte[length];
readFully(b);
- return new String(b, 0, length, "UTF-8");
+ result = decodeChars(b, 0, length);
}
}
catch (UnsupportedEncodingException uee)
{
throw new AssertionError(uee);
}
+ return result;
}
public void addDummyByte()