New code style. No functional changes.

This commit is contained in:
Harald Kuhr
2011-02-17 12:36:40 +01:00
parent 191643a36c
commit 43cc440e67
60 changed files with 1671 additions and 1665 deletions

View File

@@ -41,21 +41,24 @@ import java.util.ArrayList;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/AbstractImageSource.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/AbstractImageSource.java#1 $
*/ */
public abstract class AbstractImageSource implements ImageProducer { public abstract class AbstractImageSource implements ImageProducer {
private List<ImageConsumer> mConsumers = new ArrayList<ImageConsumer>(); private List<ImageConsumer> consumers = new ArrayList<ImageConsumer>();
protected int mWidth; protected int width;
protected int mHeight; protected int height;
protected int mXOff; protected int xOff;
protected int mYOff; protected int yOff;
// ImageProducer interface // ImageProducer interface
public void addConsumer(ImageConsumer pConsumer) { public void addConsumer(final ImageConsumer pConsumer) {
if (mConsumers.contains(pConsumer)) { if (consumers.contains(pConsumer)) {
return; return;
} }
mConsumers.add(pConsumer);
consumers.add(pConsumer);
try { try {
initConsumer(pConsumer); initConsumer(pConsumer);
sendPixels(pConsumer); sendPixels(pConsumer);
if (isConsumer(pConsumer)) { if (isConsumer(pConsumer)) {
pConsumer.imageComplete(ImageConsumer.STATICIMAGEDONE); pConsumer.imageComplete(ImageConsumer.STATICIMAGEDONE);
@@ -68,34 +71,35 @@ public abstract class AbstractImageSource implements ImageProducer {
} }
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
if (isConsumer(pConsumer)) { if (isConsumer(pConsumer)) {
pConsumer.imageComplete(ImageConsumer.IMAGEERROR); pConsumer.imageComplete(ImageConsumer.IMAGEERROR);
} }
} }
} }
public void removeConsumer(ImageConsumer pConsumer) { public void removeConsumer(final ImageConsumer pConsumer) {
mConsumers.remove(pConsumer); consumers.remove(pConsumer);
} }
/** /**
* This implementation silently ignores this instruction. If pixeldata is * This implementation silently ignores this instruction. If pixel data is
* not in TDLR order by default, subclasses must override this method. * not in TDLR order by default, subclasses must override this method.
* *
* @param pConsumer the consumer that requested the resend * @param pConsumer the consumer that requested the resend
* *
* @see ImageProducer#requestTopDownLeftRightResend(java.awt.image.ImageConsumer) * @see ImageProducer#requestTopDownLeftRightResend(java.awt.image.ImageConsumer)
*/ */
public void requestTopDownLeftRightResend(ImageConsumer pConsumer) { public void requestTopDownLeftRightResend(final ImageConsumer pConsumer) {
// ignore // ignore
} }
public void startProduction(ImageConsumer pConsumer) { public void startProduction(final ImageConsumer pConsumer) {
addConsumer(pConsumer); addConsumer(pConsumer);
} }
public boolean isConsumer(ImageConsumer pConsumer) { public boolean isConsumer(final ImageConsumer pConsumer) {
return mConsumers.contains(pConsumer); return consumers.contains(pConsumer);
} }
protected abstract void initConsumer(ImageConsumer pConsumer); protected abstract void initConsumer(ImageConsumer pConsumer);

View File

@@ -47,33 +47,34 @@ import java.io.IOException;
*/ */
public class AreaAverageOp implements BufferedImageOp, RasterOp { public class AreaAverageOp implements BufferedImageOp, RasterOp {
final private int mWidth; final private int width;
final private int mHeight; final private int height;
private Rectangle mSourceRegion; private Rectangle sourceRegion;
public AreaAverageOp(final int pWidth, final int pHeight) { public AreaAverageOp(final int pWidth, final int pHeight) {
mWidth = pWidth; width = pWidth;
mHeight = pHeight; height = pHeight;
} }
public Rectangle getSourceRegion() { public Rectangle getSourceRegion() {
if (mSourceRegion == null) { if (sourceRegion == null) {
return null; return null;
} }
return new Rectangle(mSourceRegion);
return new Rectangle(sourceRegion);
} }
public void setSourceRegion(final Rectangle pSourceRegion) { public void setSourceRegion(final Rectangle pSourceRegion) {
if (pSourceRegion == null) { if (pSourceRegion == null) {
mSourceRegion = null; sourceRegion = null;
} }
else { else {
if (mSourceRegion == null) { if (sourceRegion == null) {
mSourceRegion = new Rectangle(pSourceRegion); sourceRegion = new Rectangle(pSourceRegion);
} }
else { else {
mSourceRegion.setBounds(pSourceRegion); sourceRegion.setBounds(pSourceRegion);
} }
} }
} }
@@ -93,7 +94,7 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
// Straight-forward version // Straight-forward version
//Image scaled = src.getScaledInstance(mWidth, mHeight, Image.SCALE_AREA_AVERAGING); //Image scaled = src.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
//ImageUtil.drawOnto(result, scaled); //ImageUtil.drawOnto(result, scaled);
//result = new BufferedImageFactory(scaled).getBufferedImage(); //result = new BufferedImageFactory(scaled).getBufferedImage();
@@ -104,7 +105,7 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
AffineTransform xform = null; AffineTransform xform = null;
int w = src.getWidth(); int w = src.getWidth();
int h = src.getHeight(); int h = src.getHeight();
while (w / 2 > mWidth && h / 2 > mHeight) { while (w / 2 > width && h / 2 > height) {
w /= 2; w /= 2;
h /= 2; h /= 2;
@@ -129,7 +130,7 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
src = temp.getSubimage(0, 0, w, h); src = temp.getSubimage(0, 0, w, h);
} }
resample(src, result, AffineTransform.getScaleInstance(mWidth / (double) w, mHeight / (double) h)); resample(src, result, AffineTransform.getScaleInstance(width / (double) w, height / (double) h));
*/ */
// The real version // The real version
@@ -160,11 +161,11 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
private WritableRaster filterImpl(Raster src, WritableRaster dest) { private WritableRaster filterImpl(Raster src, WritableRaster dest) {
//System.out.println("src: " + src); //System.out.println("src: " + src);
//System.out.println("dest: " + dest); //System.out.println("dest: " + dest);
if (mSourceRegion != null) { if (sourceRegion != null) {
int cx = mSourceRegion.x; int cx = sourceRegion.x;
int cy = mSourceRegion.y; int cy = sourceRegion.y;
int cw = mSourceRegion.width; int cw = sourceRegion.width;
int ch = mSourceRegion.height; int ch = sourceRegion.height;
boolean same = src == dest; boolean same = src == dest;
dest = dest.createWritableChild(cx, cy, cw, ch, 0, 0, null); dest = dest.createWritableChild(cx, cy, cw, ch, 0, 0, null);
@@ -179,11 +180,11 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
// TODO: This don't work too well.. // TODO: This don't work too well..
// The thing is that the step length and the scan length will vary, for // The thing is that the step length and the scan length will vary, for
// non-even (1/2, 1/4, 1/8 etc) resampling // non-even (1/2, 1/4, 1/8 etc) resampling
int widthSteps = (width + mWidth - 1) / mWidth; int widthSteps = (width + this.width - 1) / this.width;
int heightSteps = (height + mHeight - 1) / mHeight; int heightSteps = (height + this.height - 1) / this.height;
final boolean oddX = width % mWidth != 0; final boolean oddX = width % this.width != 0;
final boolean oddY = height % mHeight != 0; final boolean oddY = height % this.height != 0;
final int dataElements = src.getNumDataElements(); final int dataElements = src.getNumDataElements();
final int bands = src.getNumBands(); final int bands = src.getNumBands();
@@ -210,16 +211,16 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
} }
} }
for (int y = 0; y < mHeight; y++) { for (int y = 0; y < this.height; y++) {
if (!oddY || y < mHeight) { if (!oddY || y < this.height) {
scanH = heightSteps; scanH = heightSteps;
} }
else { else {
scanH = height - (y * heightSteps); scanH = height - (y * heightSteps);
} }
for (int x = 0; x < mWidth; x++) { for (int x = 0; x < this.width; x++) {
if (!oddX || x < mWidth) { if (!oddX || x < this.width) {
scanW = widthSteps; scanW = widthSteps;
} }
else { else {
@@ -243,8 +244,8 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
// //
//System.err.println("width: " + width); //System.err.println("width: " + width);
//System.err.println("height: " + height); //System.err.println("height: " + height);
//System.err.println("mWidth: " + mWidth); //System.err.println("width: " + width);
//System.err.println("mHeight: " + mHeight); //System.err.println("height: " + height);
// //
//e.printStackTrace(); //e.printStackTrace();
continue; continue;
@@ -382,20 +383,20 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) { public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
ColorModel cm = destCM != null ? destCM : src.getColorModel(); ColorModel cm = destCM != null ? destCM : src.getColorModel();
return new BufferedImage(cm, return new BufferedImage(cm,
ImageUtil.createCompatibleWritableRaster(src, cm, mWidth, mHeight), ImageUtil.createCompatibleWritableRaster(src, cm, width, height),
cm.isAlphaPremultiplied(), null); cm.isAlphaPremultiplied(), null);
} }
public WritableRaster createCompatibleDestRaster(Raster src) { public WritableRaster createCompatibleDestRaster(Raster src) {
return src.createCompatibleWritableRaster(mWidth, mHeight); return src.createCompatibleWritableRaster(width, height);
} }
public Rectangle2D getBounds2D(Raster src) { public Rectangle2D getBounds2D(Raster src) {
return new Rectangle(mWidth, mHeight); return new Rectangle(width, height);
} }
public Rectangle2D getBounds2D(BufferedImage src) { public Rectangle2D getBounds2D(BufferedImage src) {
return new Rectangle(mWidth, mHeight); return new Rectangle(width, height);
} }
public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {

View File

@@ -67,7 +67,7 @@ public class BrightnessContrastFilter extends RGBImageFilter {
} }
// Use a precalculated lookup table for performace // Use a precalculated lookup table for performace
private int[] mLUT = null; private final int[] LUT;
/** /**
* Creates a BrightnessContrastFilter with default values * Creates a BrightnessContrastFilter with default values
@@ -105,7 +105,7 @@ public class BrightnessContrastFilter extends RGBImageFilter {
* {@code -1.0,..,0.0,..,1.0}. * {@code -1.0,..,0.0,..,1.0}.
*/ */
public BrightnessContrastFilter(float pBrightness, float pContrast) { public BrightnessContrastFilter(float pBrightness, float pContrast) {
mLUT = createLUT(pBrightness, pContrast); LUT = createLUT(pBrightness, pContrast);
} }
private static int[] createLUT(float pBrightness, float pContrast) { private static int[] createLUT(float pBrightness, float pContrast) {
@@ -157,9 +157,9 @@ public class BrightnessContrastFilter extends RGBImageFilter {
int b = pARGB & 0xFF; int b = pARGB & 0xFF;
// Scale to new contrast // Scale to new contrast
r = mLUT[r]; r = LUT[r];
g = mLUT[g]; g = LUT[g];
b = mLUT[b]; b = LUT[b];
// Return ARGB pixel, leave transparency as is // Return ARGB pixel, leave transparency as is
return (pARGB & 0xFF000000) | (r << 16) | (g << 8) | b; return (pARGB & 0xFF000000) | (r << 16) | (g << 8) | b;

View File

@@ -28,11 +28,14 @@
package com.twelvemonkeys.image; package com.twelvemonkeys.image;
import com.twelvemonkeys.lang.Validate;
import java.awt.*; import java.awt.*;
import java.awt.image.*; import java.awt.image.*;
import java.util.*;
import java.util.List;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.EventListener;
import java.util.Hashtable;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
/** /**
@@ -52,50 +55,53 @@ import java.util.concurrent.CopyOnWriteArrayList;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/BufferedImageFactory.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/BufferedImageFactory.java#1 $
*/ */
public final class BufferedImageFactory { public final class BufferedImageFactory {
private List<ProgressListener> mListeners; private List<ProgressListener> listeners;
private int mPercentageDone; private int percentageDone;
private ImageProducer mProducer; private ImageProducer producer;
private boolean mError; private boolean error;
private boolean mFetching; private volatile boolean fetching;
private boolean mReadColorModelOnly; private boolean readColorModelOnly;
private int mX = 0; private int x = 0;
private int mY = 0; private int y = 0;
private int mWidth = -1; private int width = -1;
private int mHeight = -1; private int height = -1;
private int mXSub = 1; private int xSub = 1;
private int mYSub = 1; private int ySub = 1;
private int mOffset; private int offset;
private int mScanSize; private int scanSize;
private ColorModel mSourceColorModel; private ColorModel sourceColorModel;
private Hashtable mSourceProperties; // ImageConsumer API dictates Hashtable private Hashtable sourceProperties; // ImageConsumer API dictates Hashtable
private Object mSourcePixels; private Object sourcePixels;
private BufferedImage mBuffered; private BufferedImage buffered;
private ColorModel mColorModel; private ColorModel colorModel;
// NOTE: Just to not expose the inheritance // NOTE: Just to not expose the inheritance
private final Consumer mConsumer = new Consumer(); private final Consumer consumer = new Consumer();
/** /**
* Creates a {@code BufferedImageFactory}. * Creates a {@code BufferedImageFactory}.
* @param pSource the source image * @param pSource the source image
* @throws IllegalArgumentException if {@code pSource == null}
*/ */
public BufferedImageFactory(final Image pSource) { public BufferedImageFactory(final Image pSource) {
this(pSource.getSource()); this(pSource != null ? pSource.getSource() : null);
} }
/** /**
* Creates a {@code BufferedImageFactory}. * Creates a {@code BufferedImageFactory}.
* @param pSource the source image producer * @param pSource the source image producer
* @throws IllegalArgumentException if {@code pSource == null}
*/ */
public BufferedImageFactory(final ImageProducer pSource) { public BufferedImageFactory(final ImageProducer pSource) {
mProducer = pSource; Validate.notNull(pSource, "source");
producer = pSource;
} }
/** /**
@@ -109,7 +115,7 @@ public final class BufferedImageFactory {
*/ */
public BufferedImage getBufferedImage() throws ImageConversionException { public BufferedImage getBufferedImage() throws ImageConversionException {
doFetch(false); doFetch(false);
return mBuffered; return buffered;
} }
/** /**
@@ -123,7 +129,7 @@ public final class BufferedImageFactory {
*/ */
public ColorModel getColorModel() throws ImageConversionException { public ColorModel getColorModel() throws ImageConversionException {
doFetch(true); doFetch(true);
return mBuffered != null ? mBuffered.getColorModel() : mColorModel; return buffered != null ? buffered.getColorModel() : colorModel;
} }
/** /**
@@ -131,15 +137,15 @@ public final class BufferedImageFactory {
*/ */
public void dispose() { public void dispose() {
freeResources(); freeResources();
mBuffered = null; buffered = null;
mColorModel = null; colorModel = null;
} }
/** /**
* Aborts the image production. * Aborts the image production.
*/ */
public void abort() { public void abort() {
mConsumer.imageComplete(ImageConsumer.IMAGEABORTED); consumer.imageComplete(ImageConsumer.IMAGEABORTED);
} }
/** /**
@@ -149,14 +155,14 @@ public final class BufferedImageFactory {
*/ */
public void setSourceRegion(final Rectangle pRegion) { public void setSourceRegion(final Rectangle pRegion) {
// Re-fetch everything, if region changed // Re-fetch everything, if region changed
if (mX != pRegion.x || mY != pRegion.y || mWidth != pRegion.width || mHeight != pRegion.height) { if (x != pRegion.x || y != pRegion.y || width != pRegion.width || height != pRegion.height) {
dispose(); dispose();
} }
mX = pRegion.x; x = pRegion.x;
mY = pRegion.y; y = pRegion.y;
mWidth = pRegion.width; width = pRegion.width;
mHeight = pRegion.height; height = pRegion.height;
} }
/** /**
@@ -167,50 +173,51 @@ public final class BufferedImageFactory {
*/ */
public void setSourceSubsampling(int pXSub, int pYSub) { public void setSourceSubsampling(int pXSub, int pYSub) {
// Re-fetch everything, if subsampling changed // Re-fetch everything, if subsampling changed
if (mXSub != pXSub || mYSub != pYSub) { if (xSub != pXSub || ySub != pYSub) {
dispose(); dispose();
} }
if (pXSub > 1) { if (pXSub > 1) {
mXSub = pXSub; xSub = pXSub;
} }
if (pYSub > 1) { if (pYSub > 1) {
mYSub = pYSub; ySub = pYSub;
} }
} }
private synchronized void doFetch(boolean pColorModelOnly) throws ImageConversionException { private synchronized void doFetch(boolean pColorModelOnly) throws ImageConversionException {
if (!mFetching && (!pColorModelOnly && mBuffered == null || mBuffered == null && mSourceColorModel == null)) { if (!fetching && (!pColorModelOnly && buffered == null || buffered == null && sourceColorModel == null)) {
// NOTE: Subsampling is only applied if extracting full image // NOTE: Subsampling is only applied if extracting full image
if (!pColorModelOnly && (mXSub > 1 || mYSub > 1)) { if (!pColorModelOnly && (xSub > 1 || ySub > 1)) {
// If only sampling a region, the region must be scaled too // If only sampling a region, the region must be scaled too
if (mWidth > 0 && mHeight > 0) { if (width > 0 && height > 0) {
mWidth = (mWidth + mXSub - 1) / mXSub; width = (width + xSub - 1) / xSub;
mHeight = (mHeight + mYSub - 1) / mYSub; height = (height + ySub - 1) / ySub;
mX = (mX + mXSub - 1) / mXSub; x = (x + xSub - 1) / xSub;
mY = (mY + mYSub - 1) / mYSub; y = (y + ySub - 1) / ySub;
} }
mProducer = new FilteredImageSource(mProducer, new SubsamplingFilter(mXSub, mYSub)); producer = new FilteredImageSource(producer, new SubsamplingFilter(xSub, ySub));
} }
// Start fetching // Start fetching
mFetching = true; fetching = true;
mReadColorModelOnly = pColorModelOnly; readColorModelOnly = pColorModelOnly;
mProducer.startProduction(mConsumer); // Note: If single-thread (synchronous), this call will block
producer.startProduction(consumer); // Note: If single-thread (synchronous), this call will block
// Wait until the producer wakes us up, by calling imageComplete // Wait until the producer wakes us up, by calling imageComplete
while (mFetching) { while (fetching) {
try { try {
wait(); wait(200l);
} }
catch (InterruptedException e) { catch (InterruptedException e) {
throw new ImageConversionException("Image conversion aborted: " + e.getMessage(), e); throw new ImageConversionException("Image conversion aborted: " + e.getMessage(), e);
} }
} }
if (mError) { if (error) {
throw new ImageConversionException("Image conversion failed: ImageConsumer.IMAGEERROR."); throw new ImageConversionException("Image conversion failed: ImageConsumer.IMAGEERROR.");
} }
@@ -224,21 +231,21 @@ public final class BufferedImageFactory {
} }
private void createColorModel() { private void createColorModel() {
mColorModel = mSourceColorModel; colorModel = sourceColorModel;
// Clean up, in case any objects are copied/cloned, so we can free resources // Clean up, in case any objects are copied/cloned, so we can free resources
freeResources(); freeResources();
} }
private void createBuffered() { private void createBuffered() {
if (mWidth > 0 && mHeight > 0) { if (width > 0 && height > 0) {
if (mSourceColorModel != null && mSourcePixels != null) { if (sourceColorModel != null && sourcePixels != null) {
// TODO: Fix pixel size / color model problem // TODO: Fix pixel size / color model problem
WritableRaster raster = ImageUtil.createRaster(mWidth, mHeight, mSourcePixels, mSourceColorModel); WritableRaster raster = ImageUtil.createRaster(width, height, sourcePixels, sourceColorModel);
mBuffered = new BufferedImage(mSourceColorModel, raster, mSourceColorModel.isAlphaPremultiplied(), mSourceProperties); buffered = new BufferedImage(sourceColorModel, raster, sourceColorModel.isAlphaPremultiplied(), sourceProperties);
} }
else { else {
mBuffered = ImageUtil.createClear(mWidth, mHeight, null); buffered = ImageUtil.createClear(width, height, null);
} }
} }
@@ -247,21 +254,21 @@ public final class BufferedImageFactory {
} }
private void freeResources() { private void freeResources() {
mSourceColorModel = null; sourceColorModel = null;
mSourcePixels = null; sourcePixels = null;
mSourceProperties = null; sourceProperties = null;
} }
private void processProgress(int mScanline) { private void processProgress(int mScanline) {
if (mListeners != null) { if (listeners != null) {
int percent = 100 * mScanline / mHeight; int percent = 100 * mScanline / height;
//System.out.println("Progress: " + percent + "%"); //System.out.println("Progress: " + percent + "%");
if (percent > mPercentageDone) { if (percent > percentageDone) {
mPercentageDone = percent; percentageDone = percent;
for (ProgressListener listener : mListeners) { for (ProgressListener listener : listeners) {
listener.progress(this, percent); listener.progress(this, percent);
} }
} }
@@ -278,11 +285,11 @@ public final class BufferedImageFactory {
return; return;
} }
if (mListeners == null) { if (listeners == null) {
mListeners = new CopyOnWriteArrayList<ProgressListener>(); listeners = new CopyOnWriteArrayList<ProgressListener>();
} }
mListeners.add(pListener); listeners.add(pListener);
} }
/** /**
@@ -295,19 +302,19 @@ public final class BufferedImageFactory {
return; return;
} }
if (mListeners == null) { if (listeners == null) {
return; return;
} }
mListeners.remove(pListener); listeners.remove(pListener);
} }
/** /**
* Removes all progress listeners from this factory. * Removes all progress listeners from this factory.
*/ */
public void removeAllProgressListeners() { public void removeAllProgressListeners() {
if (mListeners != null) { if (listeners != null) {
mListeners.clear(); listeners.clear();
} }
} }
@@ -378,21 +385,21 @@ public final class BufferedImageFactory {
} }
// Allocate array if necessary // Allocate array if necessary
if (mSourcePixels == null) { if (sourcePixels == null) {
// Allocate a suitable source pixel array // Allocate a suitable source pixel array
// TODO: Should take pixel "width" into consideration, for byte packed rasters?! // TODO: Should take pixel "width" into consideration, for byte packed rasters?!
// OR... Is anything but single-pixel models really supported by the API? // OR... Is anything but single-pixel models really supported by the API?
mSourcePixels = Array.newInstance(pPixels.getClass().getComponentType(), mWidth * mHeight); sourcePixels = Array.newInstance(pPixels.getClass().getComponentType(), width * height);
mScanSize = mWidth; scanSize = width;
mOffset = 0; offset = 0;
} }
else if (mSourcePixels.getClass() != pPixels.getClass()) { else if (sourcePixels.getClass() != pPixels.getClass()) {
throw new IllegalStateException("Only one pixel type allowed"); throw new IllegalStateException("Only one pixel type allowed");
} }
// AOI stuff // AOI stuff
if (pY < mY) { if (pY < y) {
int diff = mY - pY; int diff = y - pY;
if (diff >= pHeight) { if (diff >= pHeight) {
return; return;
} }
@@ -400,15 +407,15 @@ public final class BufferedImageFactory {
pY += diff; pY += diff;
pHeight -= diff; pHeight -= diff;
} }
if (pY + pHeight > mY + mHeight) { if (pY + pHeight > y + height) {
pHeight = (mY + mHeight) - pY; pHeight = (y + height) - pY;
if (pHeight <= 0) { if (pHeight <= 0) {
return; return;
} }
} }
if (pX < mX) { if (pX < x) {
int diff = mX - pX; int diff = x - pX;
if (diff >= pWidth) { if (diff >= pWidth) {
return; return;
} }
@@ -416,20 +423,20 @@ public final class BufferedImageFactory {
pX += diff; pX += diff;
pWidth -= diff; pWidth -= diff;
} }
if (pX + pWidth > mX + mWidth) { if (pX + pWidth > x + width) {
pWidth = (mX + mWidth) - pX; pWidth = (x + width) - pX;
if (pWidth <= 0) { if (pWidth <= 0) {
return; return;
} }
} }
int dstOffset = mOffset + (pY - mY) * mScanSize + (pX - mX); int dstOffset = offset + (pY - y) * scanSize + (pX - x);
// Do the pixel copying // Do the pixel copying
for (int i = pHeight; i > 0; i--) { for (int i = pHeight; i > 0; i--) {
System.arraycopy(pPixels, pOffset, mSourcePixels, dstOffset, pWidth); System.arraycopy(pPixels, pOffset, sourcePixels, dstOffset, pWidth);
pOffset += pScanSize; pOffset += pScanSize;
dstOffset += mScanSize; dstOffset += scanSize;
} }
processProgress(pY + pHeight); processProgress(pY + pHeight);
@@ -439,14 +446,14 @@ public final class BufferedImageFactory {
setPixelsImpl(pX, pY, pWidth, pHeight, pModel, pPixels, pOffset, pScanSize); setPixelsImpl(pX, pY, pWidth, pHeight, pModel, pPixels, pOffset, pScanSize);
} }
private void setColorModelOnce(ColorModel pModel) { private void setColorModelOnce(final ColorModel pModel) {
// NOTE: There seems to be a "bug" in AreaAveragingScaleFilter, as it // NOTE: There seems to be a "bug" in AreaAveragingScaleFilter, as it
// first passes the original color model through in setColorModel, then // first passes the original color model through in setColorModel, then
// later replaces it with the default RGB in the first setPixels call // later replaces it with the default RGB in the first setPixels call
// (this is probably allowed according to the spec, but it's a waste of time and space). // (this is probably allowed according to the spec, but it's a waste of time and space).
if (mSourceColorModel != pModel) { if (sourceColorModel != pModel) {
if (/*mSourceColorModel == null ||*/ mSourcePixels == null) { if (/*sourceColorModel == null ||*/ sourcePixels == null) {
mSourceColorModel = pModel; sourceColorModel = pModel;
} }
else { else {
throw new IllegalStateException("Change of ColorModel after pixel delivery not supported"); throw new IllegalStateException("Change of ColorModel after pixel delivery not supported");
@@ -454,23 +461,22 @@ public final class BufferedImageFactory {
} }
// If color model is all we ask for, stop now // If color model is all we ask for, stop now
if (mReadColorModelOnly) { if (readColorModelOnly) {
mConsumer.imageComplete(ImageConsumer.IMAGEABORTED); consumer.imageComplete(ImageConsumer.IMAGEABORTED);
} }
} }
@SuppressWarnings({"ThrowableInstanceNeverThrown"})
public void imageComplete(int pStatus) { public void imageComplete(int pStatus) {
mFetching = false; fetching = false;
if (mProducer != null) { if (producer != null) {
mProducer.removeConsumer(this); producer.removeConsumer(this);
} }
switch (pStatus) { switch (pStatus) {
case ImageConsumer.IMAGEERROR: case ImageConsumer.IMAGEERROR:
new Error().printStackTrace(); Thread.dumpStack();
mError = true; error = true;
break; break;
} }
@@ -484,15 +490,15 @@ public final class BufferedImageFactory {
} }
public void setDimensions(int pWidth, int pHeight) { public void setDimensions(int pWidth, int pHeight) {
if (mWidth < 0) { if (width < 0) {
mWidth = pWidth - mX; width = pWidth - x;
} }
if (mHeight < 0) { if (height < 0) {
mHeight = pHeight - mY; height = pHeight - y;
} }
// Hmm.. Special case, but is it a good idea? // Hmm.. Special case, but is it a good idea?
if (mWidth <= 0 || mHeight <= 0) { if (width <= 0 || height <= 0) {
imageComplete(ImageConsumer.STATICIMAGEDONE); imageComplete(ImageConsumer.STATICIMAGEDONE);
} }
} }
@@ -530,7 +536,7 @@ public final class BufferedImageFactory {
} }
public void setProperties(Hashtable pProperties) { public void setProperties(Hashtable pProperties) {
mSourceProperties = pProperties; sourceProperties = pProperties;
} }
} }
} }

View File

@@ -28,6 +28,8 @@
package com.twelvemonkeys.image; package com.twelvemonkeys.image;
import com.twelvemonkeys.lang.Validate;
import javax.swing.Icon; import javax.swing.Icon;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.*; import java.awt.*;
@@ -41,51 +43,44 @@ import java.awt.geom.AffineTransform;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/BufferedImageIcon.java#2 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/BufferedImageIcon.java#2 $
*/ */
public class BufferedImageIcon implements Icon { public class BufferedImageIcon implements Icon {
private final BufferedImage mImage; private final BufferedImage image;
private int mWidth; private int width;
private int mHeight; private int height;
private final boolean mFast; private final boolean fast;
public BufferedImageIcon(BufferedImage pImage) { public BufferedImageIcon(BufferedImage pImage) {
this(pImage, pImage.getWidth(), pImage.getHeight()); this(pImage, pImage.getWidth(), pImage.getHeight());
} }
public BufferedImageIcon(BufferedImage pImage, int pWidth, int pHeight) { public BufferedImageIcon(BufferedImage pImage, int pWidth, int pHeight) {
if (pImage == null) { image = Validate.notNull(pImage, "image");
throw new IllegalArgumentException("image == null"); width = Validate.isTrue(pWidth > 0, pWidth, "width must be positive: %d");
} height = Validate.isTrue(pHeight > 0, pHeight, "height must be positive: %d");
if (pWidth <= 0 || pHeight <= 0) {
throw new IllegalArgumentException("Icon size must be positive");
}
mImage = pImage; fast = image.getWidth() == width && image.getHeight() == height;
mWidth = pWidth;
mHeight = pHeight;
mFast = pImage.getWidth() == mWidth && pImage.getHeight() == mHeight;
} }
public int getIconHeight() { public int getIconHeight() {
return mHeight; return height;
} }
public int getIconWidth() { public int getIconWidth() {
return mWidth; return width;
} }
public void paintIcon(Component c, Graphics g, int x, int y) { public void paintIcon(Component c, Graphics g, int x, int y) {
if (mFast || !(g instanceof Graphics2D)) { if (fast || !(g instanceof Graphics2D)) {
//System.out.println("Scaling fast"); //System.out.println("Scaling fast");
g.drawImage(mImage, x, y, mWidth, mHeight, null); g.drawImage(image, x, y, width, height, null);
} }
else { else {
//System.out.println("Scaling using interpolation"); //System.out.println("Scaling using interpolation");
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
AffineTransform xform = AffineTransform.getTranslateInstance(x, y); AffineTransform xform = AffineTransform.getTranslateInstance(x, y);
xform.scale(mWidth / (double) mImage.getWidth(), mHeight / (double) mImage.getHeight()); xform.scale(width / (double) image.getWidth(), height / (double) image.getHeight());
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR); RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(mImage, xform, null); g2.drawImage(image, xform, null);
} }
} }
} }

View File

@@ -73,14 +73,15 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
*/ */
public static final int EDGE_WRAP = 3; // as JAI BORDER_WRAP public static final int EDGE_WRAP = 3; // as JAI BORDER_WRAP
private final Kernel mKernel; private final Kernel kernel;
private final int mEdgeCondition; private final int edgeCondition;
private final ConvolveOp mConvolve; private final ConvolveOp convolve;
public ConvolveWithEdgeOp(final Kernel pKernel, final int pEdgeCondition, final RenderingHints pHints) { public ConvolveWithEdgeOp(final Kernel pKernel, final int pEdgeCondition, final RenderingHints pHints) {
// Create convolution operation // Create convolution operation
int edge; int edge;
switch (pEdgeCondition) { switch (pEdgeCondition) {
case EDGE_REFLECT: case EDGE_REFLECT:
case EDGE_WRAP: case EDGE_WRAP:
@@ -90,9 +91,10 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
edge = pEdgeCondition; edge = pEdgeCondition;
break; break;
} }
mKernel = pKernel;
mEdgeCondition = pEdgeCondition; kernel = pKernel;
mConvolve = new ConvolveOp(pKernel, edge, pHints); edgeCondition = pEdgeCondition;
convolve = new ConvolveOp(pKernel, edge, pHints);
} }
public ConvolveWithEdgeOp(final Kernel pKernel) { public ConvolveWithEdgeOp(final Kernel pKernel) {
@@ -107,8 +109,8 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
throw new IllegalArgumentException("source image cannot be the same as the destination image"); throw new IllegalArgumentException("source image cannot be the same as the destination image");
} }
int borderX = mKernel.getWidth() / 2; int borderX = kernel.getWidth() / 2;
int borderY = mKernel.getHeight() / 2; int borderY = kernel.getHeight() / 2;
BufferedImage original = addBorder(pSource, borderX, borderY); BufferedImage original = addBorder(pSource, borderX, borderY);
@@ -126,7 +128,7 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
} }
// Do the filtering (if destination is null, a new image will be created) // Do the filtering (if destination is null, a new image will be created)
destination = mConvolve.filter(original, destination); destination = convolve.filter(original, destination);
if (pSource != original) { if (pSource != original) {
// Remove the border // Remove the border
@@ -137,7 +139,7 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
} }
private BufferedImage addBorder(final BufferedImage pOriginal, final int pBorderX, final int pBorderY) { private BufferedImage addBorder(final BufferedImage pOriginal, final int pBorderX, final int pBorderY) {
if ((mEdgeCondition & 2) == 0) { if ((edgeCondition & 2) == 0) {
return pOriginal; return pOriginal;
} }
@@ -158,7 +160,7 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
g.drawImage(pOriginal, pBorderX, pBorderY, null); g.drawImage(pOriginal, pBorderX, pBorderY, null);
// TODO: I guess we need the top/left etc, if the corner pixels are covered by the kernel // TODO: I guess we need the top/left etc, if the corner pixels are covered by the kernel
switch (mEdgeCondition) { switch (edgeCondition) {
case EDGE_REFLECT: case EDGE_REFLECT:
// Top/left (empty) // Top/left (empty)
g.drawImage(pOriginal, pBorderX, 0, pBorderX + w, pBorderY, 0, 0, w, 1, null); // Top/center g.drawImage(pOriginal, pBorderX, 0, pBorderX + w, pBorderY, 0, 0, w, 1, null); // Top/center
@@ -186,7 +188,7 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
g.drawImage(pOriginal, w + pBorderX, h + pBorderY, null); // Bottom/right g.drawImage(pOriginal, w + pBorderX, h + pBorderY, null); // Bottom/right
break; break;
default: default:
throw new IllegalArgumentException("Illegal edge operation " + mEdgeCondition); throw new IllegalArgumentException("Illegal edge operation " + edgeCondition);
} }
} }
@@ -206,39 +208,39 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
* @see #EDGE_WRAP * @see #EDGE_WRAP
*/ */
public int getEdgeCondition() { public int getEdgeCondition() {
return mEdgeCondition; return edgeCondition;
} }
public WritableRaster filter(final Raster pSource, final WritableRaster pDestination) { public WritableRaster filter(final Raster pSource, final WritableRaster pDestination) {
return mConvolve.filter(pSource, pDestination); return convolve.filter(pSource, pDestination);
} }
public BufferedImage createCompatibleDestImage(final BufferedImage pSource, final ColorModel pDesinationColorModel) { public BufferedImage createCompatibleDestImage(final BufferedImage pSource, final ColorModel pDesinationColorModel) {
return mConvolve.createCompatibleDestImage(pSource, pDesinationColorModel); return convolve.createCompatibleDestImage(pSource, pDesinationColorModel);
} }
public WritableRaster createCompatibleDestRaster(final Raster pSource) { public WritableRaster createCompatibleDestRaster(final Raster pSource) {
return mConvolve.createCompatibleDestRaster(pSource); return convolve.createCompatibleDestRaster(pSource);
} }
public Rectangle2D getBounds2D(final BufferedImage pSource) { public Rectangle2D getBounds2D(final BufferedImage pSource) {
return mConvolve.getBounds2D(pSource); return convolve.getBounds2D(pSource);
} }
public Rectangle2D getBounds2D(final Raster pSource) { public Rectangle2D getBounds2D(final Raster pSource) {
return mConvolve.getBounds2D(pSource); return convolve.getBounds2D(pSource);
} }
public Point2D getPoint2D(final Point2D pSourcePoint, final Point2D pDestinationPoint) { public Point2D getPoint2D(final Point2D pSourcePoint, final Point2D pDestinationPoint) {
return mConvolve.getPoint2D(pSourcePoint, pDestinationPoint); return convolve.getPoint2D(pSourcePoint, pDestinationPoint);
} }
public RenderingHints getRenderingHints() { public RenderingHints getRenderingHints() {
return mConvolve.getRenderingHints(); return convolve.getRenderingHints();
} }
public Kernel getKernel() { public Kernel getKernel() {
return mConvolve.getKernel(); return convolve.getKernel();
} }
} }

View File

@@ -51,7 +51,7 @@ import java.awt.image.WritableRaster;
*/ */
public class CopyDither implements BufferedImageOp, RasterOp { public class CopyDither implements BufferedImageOp, RasterOp {
protected IndexColorModel mIndexColorModel = null; protected IndexColorModel indexColorModel = null;
/** /**
* Creates a {@code CopyDither}, using the given * Creates a {@code CopyDither}, using the given
@@ -61,7 +61,7 @@ public class CopyDither implements BufferedImageOp, RasterOp {
*/ */
public CopyDither(IndexColorModel pICM) { public CopyDither(IndexColorModel pICM) {
// Store colormodel // Store colormodel
mIndexColorModel = pICM; indexColorModel = pICM;
} }
/** /**
@@ -83,17 +83,12 @@ public class CopyDither implements BufferedImageOp, RasterOp {
* @throws ImageFilterException if {@code pDestCM} is not {@code null} or * @throws ImageFilterException if {@code pDestCM} is not {@code null} or
* an instance of {@code IndexColorModel}. * an instance of {@code IndexColorModel}.
*/ */
public final BufferedImage createCompatibleDestImage(BufferedImage pSource, public final BufferedImage createCompatibleDestImage(BufferedImage pSource, ColorModel pDestCM) {
ColorModel pDestCM) {
if (pDestCM == null) { if (pDestCM == null) {
return new BufferedImage(pSource.getWidth(), pSource.getHeight(), return new BufferedImage(pSource.getWidth(), pSource.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, indexColorModel);
BufferedImage.TYPE_BYTE_INDEXED,
mIndexColorModel);
} }
else if (pDestCM instanceof IndexColorModel) { else if (pDestCM instanceof IndexColorModel) {
return new BufferedImage(pSource.getWidth(), pSource.getHeight(), return new BufferedImage(pSource.getWidth(), pSource.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, (IndexColorModel) pDestCM);
BufferedImage.TYPE_BYTE_INDEXED,
(IndexColorModel) pDestCM);
} }
else { else {
throw new ImageFilterException("Only IndexColorModel allowed."); throw new ImageFilterException("Only IndexColorModel allowed.");
@@ -112,13 +107,7 @@ public class CopyDither implements BufferedImageOp, RasterOp {
return createCompatibleDestRaster(pSrc, getICM(pSrc)); return createCompatibleDestRaster(pSrc, getICM(pSrc));
} }
public final WritableRaster createCompatibleDestRaster(Raster pSrc, public final WritableRaster createCompatibleDestRaster(Raster pSrc, IndexColorModel pIndexColorModel) {
IndexColorModel pIndexColorModel) {
/*
return new BufferedImage(pSrc.getWidth(), pSrc.getHeight(),
BufferedImage.TYPE_BYTE_INDEXED,
pIndexColorModel).getRaster();
*/
return pIndexColorModel.createCompatibleWritableRaster(pSrc.getWidth(), pSrc.getHeight()); return pIndexColorModel.createCompatibleWritableRaster(pSrc.getWidth(), pSrc.getHeight());
} }
@@ -207,8 +196,7 @@ public class CopyDither implements BufferedImageOp, RasterOp {
* @return the destination image, or a new image, if {@code pDest} was * @return the destination image, or a new image, if {@code pDest} was
* {@code null}. * {@code null}.
*/ */
public final BufferedImage filter(BufferedImage pSource, public final BufferedImage filter(BufferedImage pSource, BufferedImage pDest) {
BufferedImage pDest) {
// Create destination image, if none provided // Create destination image, if none provided
if (pDest == null) { if (pDest == null) {
pDest = createCompatibleDestImage(pSource, getICM(pSource)); pDest = createCompatibleDestImage(pSource, getICM(pSource));
@@ -238,16 +226,17 @@ public class CopyDither implements BufferedImageOp, RasterOp {
} }
private IndexColorModel getICM(BufferedImage pSource) { private IndexColorModel getICM(BufferedImage pSource) {
return (mIndexColorModel != null ? mIndexColorModel : IndexImage.getIndexColorModel(pSource, 256, IndexImage.TRANSPARENCY_BITMASK | IndexImage.COLOR_SELECTION_QUALITY)); return (indexColorModel != null ? indexColorModel : IndexImage.getIndexColorModel(pSource, 256, IndexImage.TRANSPARENCY_BITMASK | IndexImage.COLOR_SELECTION_QUALITY));
} }
private IndexColorModel getICM(Raster pSource) { private IndexColorModel getICM(Raster pSource) {
return (mIndexColorModel != null ? mIndexColorModel : createIndexColorModel(pSource)); return (indexColorModel != null ? indexColorModel : createIndexColorModel(pSource));
} }
private IndexColorModel createIndexColorModel(Raster pSource) { private IndexColorModel createIndexColorModel(Raster pSource) {
BufferedImage image = new BufferedImage(pSource.getWidth(), pSource.getHeight(), BufferedImage image = new BufferedImage(pSource.getWidth(), pSource.getHeight(), BufferedImage.TYPE_INT_ARGB);
BufferedImage.TYPE_INT_ARGB);
image.setData(pSource); image.setData(pSource);
return IndexImage.getIndexColorModel(image, 256, IndexImage.TRANSPARENCY_BITMASK | IndexImage.COLOR_SELECTION_QUALITY); return IndexImage.getIndexColorModel(image, 256, IndexImage.TRANSPARENCY_BITMASK | IndexImage.COLOR_SELECTION_QUALITY);
} }
@@ -261,8 +250,7 @@ public class CopyDither implements BufferedImageOp, RasterOp {
* @return the destination raster, or a new raster, if {@code pDest} was * @return the destination raster, or a new raster, if {@code pDest} was
* {@code null}. * {@code null}.
*/ */
public final WritableRaster filter(final Raster pSource, WritableRaster pDest, public final WritableRaster filter(final Raster pSource, WritableRaster pDest, IndexColorModel pColorModel) {
IndexColorModel pColorModel) {
int width = pSource.getWidth(); int width = pSource.getWidth();
int height = pSource.getHeight(); int height = pSource.getHeight();
@@ -292,6 +280,7 @@ public class CopyDither implements BufferedImageOp, RasterOp {
pDest.setDataElements(x, y, pixel); pDest.setDataElements(x, y, pixel);
} }
} }
return pDest; return pDest;
} }
} }

View File

@@ -41,8 +41,8 @@ import java.util.Random;
*/ */
public class DiffusionDither implements BufferedImageOp, RasterOp { public class DiffusionDither implements BufferedImageOp, RasterOp {
protected IndexColorModel mIndexColorModel = null; protected IndexColorModel indexColorModel = null;
private boolean mAlternateScans = true; private boolean alternateScans = true;
private static final int FS_SCALE = 1 << 8; private static final int FS_SCALE = 1 << 8;
private static final Random RANDOM = new Random(); private static final Random RANDOM = new Random();
@@ -54,7 +54,7 @@ public class DiffusionDither implements BufferedImageOp, RasterOp {
*/ */
public DiffusionDither(IndexColorModel pICM) { public DiffusionDither(IndexColorModel pICM) {
// Store colormodel // Store colormodel
mIndexColorModel = pICM; indexColorModel = pICM;
} }
/** /**
@@ -74,7 +74,7 @@ public class DiffusionDither implements BufferedImageOp, RasterOp {
* @param pUse {@code true} if scan mode should be alternating left/right * @param pUse {@code true} if scan mode should be alternating left/right
*/ */
public void setAlternateScans(boolean pUse) { public void setAlternateScans(boolean pUse) {
mAlternateScans = pUse; alternateScans = pUse;
} }
/** /**
@@ -252,10 +252,10 @@ public class DiffusionDither implements BufferedImageOp, RasterOp {
} }
private IndexColorModel getICM(BufferedImage pSource) { private IndexColorModel getICM(BufferedImage pSource) {
return (mIndexColorModel != null ? mIndexColorModel : IndexImage.getIndexColorModel(pSource, 256, IndexImage.TRANSPARENCY_BITMASK)); return (indexColorModel != null ? indexColorModel : IndexImage.getIndexColorModel(pSource, 256, IndexImage.TRANSPARENCY_BITMASK));
} }
private IndexColorModel getICM(Raster pSource) { private IndexColorModel getICM(Raster pSource) {
return (mIndexColorModel != null ? mIndexColorModel : createIndexColorModel(pSource)); return (indexColorModel != null ? indexColorModel : createIndexColorModel(pSource));
} }
private IndexColorModel createIndexColorModel(Raster pSource) { private IndexColorModel createIndexColorModel(Raster pSource) {
@@ -456,7 +456,7 @@ public class DiffusionDither implements BufferedImageOp, RasterOp {
mNextErr = temperr; mNextErr = temperr;
// Toggle direction // Toggle direction
if (mAlternateScans) { if (alternateScans) {
forward = !forward; forward = !forward;
} }
} }

View File

@@ -48,8 +48,8 @@ public class GrayFilter extends RGBImageFilter {
canFilterIndexColorModel = true; canFilterIndexColorModel = true;
} }
private int mLow = 0; private int low = 0;
private float mRange = 1.0f; private float range = 1.0f;
/** /**
* Constructs a GrayFilter using ITU color-conversion. * Constructs a GrayFilter using ITU color-conversion.
@@ -82,8 +82,8 @@ public class GrayFilter extends RGBImageFilter {
pHigh = 1f; pHigh = 1f;
} }
mLow = (int) (pLow * 255f); low = (int) (pLow * 255f);
mRange = pHigh - pLow; range = pHigh - pLow;
} }
@@ -118,9 +118,9 @@ public class GrayFilter extends RGBImageFilter {
//int gray = (int) ((float) (r + g + b) / 3.0f); //int gray = (int) ((float) (r + g + b) / 3.0f);
if (mRange != 1.0f) { if (range != 1.0f) {
// Apply range // Apply range
gray = mLow + (int) (gray * mRange); gray = low + (int) (gray * range);
} }
// Return ARGB pixel // Return ARGB pixel

View File

@@ -32,42 +32,20 @@ package com.twelvemonkeys.image;
* This class wraps IllegalArgumentException as thrown by the * This class wraps IllegalArgumentException as thrown by the
* BufferedImageOp interface for more fine-grained control. * BufferedImageOp interface for more fine-grained control.
* *
* @author Harald Kuhr * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* *
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/ImageFilterException.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/ImageFilterException.java#1 $
*/ */
public class ImageFilterException extends IllegalArgumentException { public class ImageFilterException extends IllegalArgumentException {
private Throwable mCause = null; public ImageFilterException(String message) {
super(message);
public ImageFilterException(String pStr) {
super(pStr);
} }
public ImageFilterException(Throwable pT) { public ImageFilterException(Throwable cause) {
initCause(pT); super(cause);
} }
public ImageFilterException(String pStr, Throwable pT) { public ImageFilterException(String message, Throwable cause) {
super(pStr); super(message, cause);
initCause(pT);
}
public Throwable initCause(Throwable pThrowable) {
if (mCause != null) {
// May only be called once
throw new IllegalStateException();
}
else if (pThrowable == this) {
throw new IllegalArgumentException();
}
mCause = pThrowable;
// Hmmm...
return this;
}
public Throwable getCause() {
return mCause;
} }
} }

View File

@@ -32,7 +32,6 @@ import java.awt.*;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.awt.image.*; import java.awt.image.*;
import java.util.Hashtable; import java.util.Hashtable;
/** /**
@@ -354,7 +353,7 @@ public final class ImageUtil {
* The new image will have the same {@code ColorModel}, {@code Raster} and * The new image will have the same {@code ColorModel}, {@code Raster} and
* properties as the original image, if possible. * properties as the original image, if possible.
* <p/> * <p/>
* If the image is allready a {@code BufferedImage}, it is simply returned * If the image is already a {@code BufferedImage}, it is simply returned
* and no conversion takes place. * and no conversion takes place.
* *
* @param pOriginal the image to convert. * @param pOriginal the image to convert.
@@ -365,7 +364,7 @@ public final class ImageUtil {
* @throws ImageConversionException if the image cannot be converted * @throws ImageConversionException if the image cannot be converted
*/ */
public static BufferedImage toBuffered(Image pOriginal) { public static BufferedImage toBuffered(Image pOriginal) {
// Don't convert if it allready is BufferedImage // Don't convert if it already is BufferedImage
if (pOriginal instanceof BufferedImage) { if (pOriginal instanceof BufferedImage) {
return (BufferedImage) pOriginal; return (BufferedImage) pOriginal;
} }
@@ -543,9 +542,10 @@ public final class ImageUtil {
*/ */
static WritableRaster createCompatibleWritableRaster(BufferedImage pOriginal, ColorModel pModel, int mWidth, int mHeight) { static WritableRaster createCompatibleWritableRaster(BufferedImage pOriginal, ColorModel pModel, int mWidth, int mHeight) {
if (pModel == null || equals(pOriginal.getColorModel(), pModel)) { if (pModel == null || equals(pOriginal.getColorModel(), pModel)) {
int[] bOffs;
switch (pOriginal.getType()) { switch (pOriginal.getType()) {
case BufferedImage.TYPE_3BYTE_BGR: case BufferedImage.TYPE_3BYTE_BGR:
int[] bOffs = {2, 1, 0}; // NOTE: These are reversed from what the cm.createCompatibleWritableRaster would return bOffs = new int[]{2, 1, 0}; // NOTE: These are reversed from what the cm.createCompatibleWritableRaster would return
return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
mWidth, mHeight, mWidth, mHeight,
mWidth * 3, 3, mWidth * 3, 3,
@@ -557,6 +557,17 @@ public final class ImageUtil {
mWidth, mHeight, mWidth, mHeight,
mWidth * 4, 4, mWidth * 4, 4,
bOffs, null); bOffs, null);
case BufferedImage.TYPE_CUSTOM:
// Peek into the sample model to see if we have a sample model that will be incompatible with the default case
SampleModel sm = pOriginal.getRaster().getSampleModel();
if (sm instanceof ComponentSampleModel) {
bOffs = ((ComponentSampleModel) sm).getBandOffsets();
return Raster.createInterleavedRaster(sm.getDataType(),
mWidth, mHeight,
mWidth * bOffs.length, bOffs.length,
bOffs, null);
}
// Else fall through
default: default:
return pOriginal.getColorModel().createCompatibleWritableRaster(mWidth, mHeight); return pOriginal.getColorModel().createCompatibleWritableRaster(mWidth, mHeight);
} }
@@ -569,7 +580,7 @@ public final class ImageUtil {
* The new image will have the same {@code ColorModel}, {@code Raster} and * The new image will have the same {@code ColorModel}, {@code Raster} and
* properties as the original image, if possible. * properties as the original image, if possible.
* <p/> * <p/>
* If the image is allready a {@code BufferedImage} of the given type, it * If the image is already a {@code BufferedImage} of the given type, it
* is simply returned and no conversion takes place. * is simply returned and no conversion takes place.
* *
* @param pOriginal the image to convert. * @param pOriginal the image to convert.
@@ -597,7 +608,7 @@ public final class ImageUtil {
* the color model * the color model
*/ */
private static BufferedImage toBuffered(Image pOriginal, int pType, IndexColorModel pICM) { private static BufferedImage toBuffered(Image pOriginal, int pType, IndexColorModel pICM) {
// Don't convert if it allready is BufferedImage and correct type // Don't convert if it already is BufferedImage and correct type
if ((pOriginal instanceof BufferedImage) if ((pOriginal instanceof BufferedImage)
&& ((BufferedImage) pOriginal).getType() == pType && ((BufferedImage) pOriginal).getType() == pType
&& (pICM == null || equals(((BufferedImage) pOriginal).getColorModel(), pICM))) { && (pICM == null || equals(((BufferedImage) pOriginal).getColorModel(), pICM))) {
@@ -784,7 +795,7 @@ public final class ImageUtil {
* Creates a scaled instance of the given {@code Image}, and converts it to * Creates a scaled instance of the given {@code Image}, and converts it to
* a {@code BufferedImage} if needed. * a {@code BufferedImage} if needed.
* If the original image is a {@code BufferedImage} the result will have * If the original image is a {@code BufferedImage} the result will have
* same type and colormodel. Note that this implies overhead, and is * same type and color model. Note that this implies overhead, and is
* probably not useful for anything but {@code IndexColorModel} images. * probably not useful for anything but {@code IndexColorModel} images.
* *
* @param pImage the {@code Image} to scale * @param pImage the {@code Image} to scale
@@ -820,7 +831,7 @@ public final class ImageUtil {
BufferedImage scaled = createResampled(pImage, pWidth, pHeight, pHints); BufferedImage scaled = createResampled(pImage, pWidth, pHeight, pHints);
// Convert if colormodels or type differ, to behave as documented // Convert if color models or type differ, to behave as documented
if (type != scaled.getType() && type != BI_TYPE_ANY || !equals(scaled.getColorModel(), cm)) { if (type != scaled.getType() && type != BI_TYPE_ANY || !equals(scaled.getColorModel(), cm)) {
//System.out.print("Converting TYPE " + scaled.getType() + " -> " + type + "... "); //System.out.print("Converting TYPE " + scaled.getType() + " -> " + type + "... ");
//long start = System.currentTimeMillis(); //long start = System.currentTimeMillis();
@@ -965,9 +976,6 @@ public final class ImageUtil {
} }
private static int convertAWTHints(int pHints) { private static int convertAWTHints(int pHints) {
// TODO: These conversions are broken!
// box == area average
// point == replicate (or..?)
switch (pHints) { switch (pHints) {
case Image.SCALE_FAST: case Image.SCALE_FAST:
case Image.SCALE_REPLICATE: case Image.SCALE_REPLICATE:

View File

@@ -72,12 +72,12 @@ class InverseColorMap {
*/ */
final static int MAXQUANTVAL = 1 << 5; final static int MAXQUANTVAL = 1 << 5;
byte[] mRGBMapByte; byte[] rgbMapByte;
int[] mRGBMapInt; int[] rgbMapInt;
int mNumColors; int numColors;
int mMaxColor; int maxColor;
byte[] mInverseRGB; // inverse rgb color map byte[] inverseRGB; // inverse rgb color map
int mTransparentIndex = -1; int transparentIndex = -1;
/** /**
* @param pRGBColorMap the rgb color map to create inverse color map for. * @param pRGBColorMap the rgb color map to create inverse color map for.
@@ -99,11 +99,11 @@ class InverseColorMap {
* @param pTransparent the index of the transparent pixel in the map * @param pTransparent the index of the transparent pixel in the map
*/ */
InverseColorMap(byte[] pRGBColorMap, int pTransparent) { InverseColorMap(byte[] pRGBColorMap, int pTransparent) {
mRGBMapByte = pRGBColorMap; rgbMapByte = pRGBColorMap;
mNumColors = mRGBMapByte.length / 4; numColors = rgbMapByte.length / 4;
mTransparentIndex = pTransparent; transparentIndex = pTransparent;
mInverseRGB = new byte[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL]; inverseRGB = new byte[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL];
initIRGB(new int[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL]); initIRGB(new int[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL]);
} }
@@ -112,11 +112,11 @@ class InverseColorMap {
* @param pTransparent the index of the transparent pixel in the map * @param pTransparent the index of the transparent pixel in the map
*/ */
InverseColorMap(int[] pRGBColorMap, int pTransparent) { InverseColorMap(int[] pRGBColorMap, int pTransparent) {
mRGBMapInt = pRGBColorMap; rgbMapInt = pRGBColorMap;
mNumColors = mRGBMapInt.length; numColors = rgbMapInt.length;
mTransparentIndex = pTransparent; transparentIndex = pTransparent;
mInverseRGB = new byte[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL]; inverseRGB = new byte[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL];
initIRGB(new int[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL]); initIRGB(new int[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL]);
} }
@@ -130,8 +130,8 @@ class InverseColorMap {
final int xsqr = 1 << (TRUNCBITS * 2); // 64 - twice the smallest step size vale of quantized colors final int xsqr = 1 << (TRUNCBITS * 2); // 64 - twice the smallest step size vale of quantized colors
final int xsqr2 = xsqr + xsqr; final int xsqr2 = xsqr + xsqr;
for (int i = 0; i < mNumColors; ++i) { for (int i = 0; i < numColors; ++i) {
if (i == mTransparentIndex) { if (i == transparentIndex) {
// Skip the transparent pixel // Skip the transparent pixel
continue; continue;
} }
@@ -141,15 +141,15 @@ class InverseColorMap {
int blue, b, bdist, binc, bxx; int blue, b, bdist, binc, bxx;
// HaraldK 20040801: Added support for int[] // HaraldK 20040801: Added support for int[]
if (mRGBMapByte != null) { if (rgbMapByte != null) {
red = mRGBMapByte[i * 4] & 0xFF; red = rgbMapByte[i * 4] & 0xFF;
green = mRGBMapByte[i * 4 + 1] & 0xFF; green = rgbMapByte[i * 4 + 1] & 0xFF;
blue = mRGBMapByte[i * 4 + 2] & 0xFF; blue = rgbMapByte[i * 4 + 2] & 0xFF;
} }
else if (mRGBMapInt != null) { else if (rgbMapInt != null) {
red = (mRGBMapInt[i] >> 16) & 0xFF; red = (rgbMapInt[i] >> 16) & 0xFF;
green = (mRGBMapInt[i] >> 8) & 0xFF; green = (rgbMapInt[i] >> 8) & 0xFF;
blue = mRGBMapInt[i] & 0xFF; blue = rgbMapInt[i] & 0xFF;
} }
else { else {
throw new IllegalStateException("colormap == null"); throw new IllegalStateException("colormap == null");
@@ -170,7 +170,7 @@ class InverseColorMap {
for (b = 0, bdist = gdist, bxx = binc; b < MAXQUANTVAL; bdist += bxx, ++b, ++rgbI, bxx += xsqr2) { for (b = 0, bdist = gdist, bxx = binc; b < MAXQUANTVAL; bdist += bxx, ++b, ++rgbI, bxx += xsqr2) {
if (i == 0 || pTemp[rgbI] > bdist) { if (i == 0 || pTemp[rgbI] > bdist) {
pTemp[rgbI] = bdist; pTemp[rgbI] = bdist;
mInverseRGB[rgbI] = (byte) i; inverseRGB[rgbI] = (byte) i;
} }
} }
} }
@@ -187,7 +187,7 @@ class InverseColorMap {
* created inverse color map. * created inverse color map.
*/ */
public final int getIndexNearest(int pColor) { public final int getIndexNearest(int pColor) {
return mInverseRGB[((pColor >> (3 * TRUNCBITS)) & QUANTMASK_RED) + return inverseRGB[((pColor >> (3 * TRUNCBITS)) & QUANTMASK_RED) +
((pColor >> (2 * TRUNCBITS)) & QUANTMASK_GREEN) + ((pColor >> (2 * TRUNCBITS)) & QUANTMASK_GREEN) +
((pColor >> (/* 1 * */ TRUNCBITS)) & QUANTMASK_BLUE)] & 0xFF; ((pColor >> (/* 1 * */ TRUNCBITS)) & QUANTMASK_BLUE)] & 0xFF;
} }
@@ -203,7 +203,7 @@ class InverseColorMap {
*/ */
public final int getIndexNearest(int pRed, int pGreen, int pBlue) { public final int getIndexNearest(int pRed, int pGreen, int pBlue) {
// NOTE: the third line in expression for blue is shifting DOWN not UP. // NOTE: the third line in expression for blue is shifting DOWN not UP.
return mInverseRGB[((pRed << (2 * QUANTBITS - TRUNCBITS)) & QUANTMASK_RED) + return inverseRGB[((pRed << (2 * QUANTBITS - TRUNCBITS)) & QUANTMASK_RED) +
((pGreen << (/* 1 * */ QUANTBITS - TRUNCBITS)) & QUANTMASK_GREEN) + ((pGreen << (/* 1 * */ QUANTBITS - TRUNCBITS)) & QUANTMASK_GREEN) +
((pBlue >> (TRUNCBITS)) & QUANTMASK_BLUE)] & 0xFF; ((pBlue >> (TRUNCBITS)) & QUANTMASK_BLUE)] & 0xFF;
} }

View File

@@ -46,13 +46,13 @@ import java.awt.image.IndexColorModel;
*/ */
public class InverseColorMapIndexColorModel extends IndexColorModel { public class InverseColorMapIndexColorModel extends IndexColorModel {
protected int mRGBs[]; protected int rgbs[];
protected int mMapSize; protected int mapSize;
protected InverseColorMap mInverseMap = null; protected InverseColorMap inverseMap = null;
private final static int ALPHA_THRESHOLD = 0x80; private final static int ALPHA_THRESHOLD = 0x80;
private int mWhiteIndex = -1; private int whiteIndex = -1;
private final static int WHITE = 0x00FFFFFF; private final static int WHITE = 0x00FFFFFF;
private final static int RGB_MASK = 0x00FFFFFF; private final static int RGB_MASK = 0x00FFFFFF;
@@ -74,11 +74,11 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
ImageUtil.getTransferType(pColorModel), ImageUtil.getTransferType(pColorModel),
pColorModel.getValidPixels()); pColorModel.getValidPixels());
mRGBs = pRGBs; rgbs = pRGBs;
mMapSize = mRGBs.length; mapSize = rgbs.length;
mInverseMap = new InverseColorMap(mRGBs); inverseMap = new InverseColorMap(rgbs);
mWhiteIndex = getWhiteIndex(); whiteIndex = getWhiteIndex();
} }
/** /**
@@ -91,6 +91,7 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
private static int[] getRGBs(IndexColorModel pColorModel) { private static int[] getRGBs(IndexColorModel pColorModel) {
int[] rgb = new int[pColorModel.getMapSize()]; int[] rgb = new int[pColorModel.getMapSize()];
pColorModel.getRGBs(rgb); pColorModel.getRGBs(rgb);
return rgb; return rgb;
} }
@@ -111,15 +112,13 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
* *
* @see IndexColorModel#IndexColorModel(int, int, int[], int, boolean, int, int) * @see IndexColorModel#IndexColorModel(int, int, int[], int, boolean, int, int)
*/ */
public InverseColorMapIndexColorModel(int pNumBits, int pSize, int[] pRGBs, public InverseColorMapIndexColorModel(int pNumBits, int pSize, int[] pRGBs, int pStart, boolean pAlpha, int pTransparentIndex, int pTransferType) {
int pStart, boolean pAlpha, int pTransparentIndex,
int pTransferType) {
super(pNumBits, pSize, pRGBs, pStart, pAlpha, pTransparentIndex, pTransferType); super(pNumBits, pSize, pRGBs, pStart, pAlpha, pTransparentIndex, pTransferType);
mRGBs = getRGBs(this); rgbs = getRGBs(this);
mMapSize = mRGBs.length; mapSize = rgbs.length;
mInverseMap = new InverseColorMap(mRGBs, pTransparentIndex); inverseMap = new InverseColorMap(rgbs, pTransparentIndex);
mWhiteIndex = getWhiteIndex(); whiteIndex = getWhiteIndex();
} }
/** /**
@@ -138,15 +137,13 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
* *
* @see IndexColorModel#IndexColorModel(int, int, byte[], byte[], byte[], int) * @see IndexColorModel#IndexColorModel(int, int, byte[], byte[], byte[], int)
*/ */
public InverseColorMapIndexColorModel(int pNumBits, int pSize, public InverseColorMapIndexColorModel(int pNumBits, int pSize, byte[] pReds, byte[] pGreens, byte[] pBlues, int pTransparentIndex) {
byte[] pReds, byte[] pGreens, byte[] pBlues,
int pTransparentIndex) {
super(pNumBits, pSize, pReds, pGreens, pBlues, pTransparentIndex); super(pNumBits, pSize, pReds, pGreens, pBlues, pTransparentIndex);
mRGBs = getRGBs(this); rgbs = getRGBs(this);
mMapSize = mRGBs.length; mapSize = rgbs.length;
mInverseMap = new InverseColorMap(mRGBs, pTransparentIndex); inverseMap = new InverseColorMap(rgbs, pTransparentIndex);
mWhiteIndex = getWhiteIndex(); whiteIndex = getWhiteIndex();
} }
/** /**
@@ -164,19 +161,18 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
* *
* @see IndexColorModel#IndexColorModel(int, int, byte[], byte[], byte[]) * @see IndexColorModel#IndexColorModel(int, int, byte[], byte[], byte[])
*/ */
public InverseColorMapIndexColorModel(int pNumBits, int pSize, public InverseColorMapIndexColorModel(int pNumBits, int pSize, byte[] pReds, byte[] pGreens, byte[] pBlues) {
byte[] pReds, byte[] pGreens, byte[] pBlues) {
super(pNumBits, pSize, pReds, pGreens, pBlues); super(pNumBits, pSize, pReds, pGreens, pBlues);
mRGBs = getRGBs(this); rgbs = getRGBs(this);
mMapSize = mRGBs.length; mapSize = rgbs.length;
mInverseMap = new InverseColorMap(mRGBs); inverseMap = new InverseColorMap(rgbs);
mWhiteIndex = getWhiteIndex(); whiteIndex = getWhiteIndex();
} }
private int getWhiteIndex() { private int getWhiteIndex() {
for (int i = 0; i < mRGBs.length; i++) { for (int i = 0; i < rgbs.length; i++) {
int color = mRGBs[i]; int color = rgbs[i];
if ((color & RGB_MASK) == WHITE) { if ((color & RGB_MASK) == WHITE) {
return i; return i;
} }
@@ -244,7 +240,6 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
* *
*/ */
public Object getDataElements(int rgb, Object pixel) { public Object getDataElements(int rgb, Object pixel) {
int alpha = (rgb>>>24); int alpha = (rgb>>>24);
int pix; int pix;
@@ -253,11 +248,11 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
} }
else { else {
int color = rgb & RGB_MASK; int color = rgb & RGB_MASK;
if (color == WHITE && mWhiteIndex != -1) { if (color == WHITE && whiteIndex != -1) {
pix = mWhiteIndex; pix = whiteIndex;
} }
else { else {
pix = mInverseMap.getIndexNearest(color); pix = inverseMap.getIndexNearest(color);
} }
} }
@@ -297,8 +292,7 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
shortObj[0] = (short) pix; shortObj[0] = (short) pix;
break; break;
default: default:
throw new UnsupportedOperationException("This method has not been " + throw new UnsupportedOperationException("This method has not been implemented for transferType " + transferType);
"implemented for transferType " + transferType);
} }
return pixel; return pixel;
} }

View File

@@ -54,11 +54,11 @@ final class MagickAccelerator {
private static final int RESAMPLE_OP = 0; private static final int RESAMPLE_OP = 0;
private static Class[] sNativeOp = new Class[1]; private static Class[] nativeOp = new Class[1];
static { static {
try { try {
sNativeOp[RESAMPLE_OP] = Class.forName("com.twelvemonkeys.image.ResampleOp"); nativeOp[RESAMPLE_OP] = Class.forName("com.twelvemonkeys.image.ResampleOp");
} }
catch (ClassNotFoundException e) { catch (ClassNotFoundException e) {
System.err.println("Could not find class: " + e); System.err.println("Could not find class: " + e);
@@ -94,8 +94,8 @@ final class MagickAccelerator {
} }
private static int getNativeOpIndex(Class pOpClass) { private static int getNativeOpIndex(Class pOpClass) {
for (int i = 0; i < sNativeOp.length; i++) { for (int i = 0; i < nativeOp.length; i++) {
if (pOpClass == sNativeOp[i]) { if (pOpClass == nativeOp[i]) {
return i; return i;
} }
} }
@@ -112,7 +112,7 @@ final class MagickAccelerator {
switch (getNativeOpIndex(pOperation.getClass())) { switch (getNativeOpIndex(pOperation.getClass())) {
case RESAMPLE_OP: case RESAMPLE_OP:
ResampleOp resample = (ResampleOp) pOperation; ResampleOp resample = (ResampleOp) pOperation;
result = resampleMagick(pInput, resample.mWidth, resample.mHeight, resample.mFilterType); result = resampleMagick(pInput, resample.width, resample.height, resample.filterType);
// NOTE: If output parameter is non-null, we have to return that // NOTE: If output parameter is non-null, we have to return that
// image, instead of result // image, instead of result

View File

@@ -33,7 +33,7 @@ import java.awt.image.*;
/** /**
* Monochrome B/W color model. * Monochrome B/W color model.
* *
* @author Harald Kuhr * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
*/ */
public class MonochromeColorModel extends IndexColorModel { public class MonochromeColorModel extends IndexColorModel {

View File

@@ -48,37 +48,37 @@ public class PixelizeOp implements BufferedImageOp, RasterOp {
// TODO: support more raster types/color models // TODO: support more raster types/color models
// TODO: This is actually an implementation of Area Averaging, without the scale... Let's extract it... // TODO: This is actually an implementation of Area Averaging, without the scale... Let's extract it...
final private int mPixelSizeX; final private int pixelSizeX;
final private int mPixelSizeY; final private int pixelSizeY;
private Rectangle mSourceRegion; private Rectangle sourceRegion;
public PixelizeOp(final int pPixelSize) { public PixelizeOp(final int pPixelSize) {
this(pPixelSize, pPixelSize); this(pPixelSize, pPixelSize);
} }
public PixelizeOp(final int pPixelSizeX, final int pPixelSizeY) { public PixelizeOp(final int pPixelSizeX, final int pPixelSizeY) {
mPixelSizeX = pPixelSizeX; pixelSizeX = pPixelSizeX;
mPixelSizeY = pPixelSizeY; pixelSizeY = pPixelSizeY;
} }
public Rectangle getSourceRegion() { public Rectangle getSourceRegion() {
if (mSourceRegion == null) { if (sourceRegion == null) {
return null; return null;
} }
return new Rectangle(mSourceRegion); return new Rectangle(sourceRegion);
} }
public void setSourceRegion(final Rectangle pSourceRegion) { public void setSourceRegion(final Rectangle pSourceRegion) {
if (pSourceRegion == null) { if (pSourceRegion == null) {
mSourceRegion = null; sourceRegion = null;
} }
else { else {
if (mSourceRegion == null) { if (sourceRegion == null) {
mSourceRegion = new Rectangle(pSourceRegion); sourceRegion = new Rectangle(pSourceRegion);
} }
else { else {
mSourceRegion.setBounds(pSourceRegion); sourceRegion.setBounds(pSourceRegion);
} }
} }
} }
@@ -107,11 +107,11 @@ public class PixelizeOp implements BufferedImageOp, RasterOp {
private WritableRaster filterImpl(Raster src, WritableRaster dest) { private WritableRaster filterImpl(Raster src, WritableRaster dest) {
//System.out.println("src: " + src); //System.out.println("src: " + src);
//System.out.println("dest: " + dest); //System.out.println("dest: " + dest);
if (mSourceRegion != null) { if (sourceRegion != null) {
int cx = mSourceRegion.x; int cx = sourceRegion.x;
int cy = mSourceRegion.y; int cy = sourceRegion.y;
int cw = mSourceRegion.width; int cw = sourceRegion.width;
int ch = mSourceRegion.height; int ch = sourceRegion.height;
boolean same = src == dest; boolean same = src == dest;
dest = dest.createWritableChild(cx, cy, cw, ch, 0, 0, null); dest = dest.createWritableChild(cx, cy, cw, ch, 0, 0, null);
@@ -122,8 +122,8 @@ public class PixelizeOp implements BufferedImageOp, RasterOp {
final int width = src.getWidth(); final int width = src.getWidth();
final int height = src.getHeight(); final int height = src.getHeight();
int w = (width + mPixelSizeX - 1) / mPixelSizeX; int w = (width + pixelSizeX - 1) / pixelSizeX;
int h = (height + mPixelSizeY - 1) / mPixelSizeY; int h = (height + pixelSizeY - 1) / pixelSizeY;
final boolean oddX = width % w != 0; final boolean oddX = width % w != 0;
final boolean oddY = height % h != 0; final boolean oddY = height % h != 0;
@@ -156,23 +156,23 @@ public class PixelizeOp implements BufferedImageOp, RasterOp {
for (int y = 0; y < h; y++) { for (int y = 0; y < h; y++) {
if (!oddY || y + 1 < h) { if (!oddY || y + 1 < h) {
scanH = mPixelSizeY; scanH = pixelSizeY;
} }
else { else {
scanH = height - (y * mPixelSizeY); scanH = height - (y * pixelSizeY);
} }
for (int x = 0; x < w; x++) { for (int x = 0; x < w; x++) {
if (!oddX || x + 1 < w) { if (!oddX || x + 1 < w) {
scanW = mPixelSizeX; scanW = pixelSizeX;
} }
else { else {
scanW = width - (x * mPixelSizeX); scanW = width - (x * pixelSizeX);
} }
final int pixelCount = scanW * scanH; final int pixelCount = scanW * scanH;
final int pixelLength = pixelCount * dataElements; final int pixelLength = pixelCount * dataElements;
data = src.getDataElements(x * mPixelSizeX, y * mPixelSizeY, scanW, scanH, data); data = src.getDataElements(x * pixelSizeX, y * pixelSizeY, scanW, scanH, data);
// NOTE: These are not neccessarily ARGB.. // NOTE: These are not neccessarily ARGB..
double valueA = 0.0; double valueA = 0.0;
@@ -277,7 +277,7 @@ public class PixelizeOp implements BufferedImageOp, RasterOp {
} }
dest.setDataElements(x * mPixelSizeX, y * mPixelSizeY, scanW, scanH, data); dest.setDataElements(x * pixelSizeX, y * pixelSizeY, scanW, scanH, data);
} }
} }
/*/ /*/

View File

@@ -60,7 +60,6 @@ import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.awt.image.*; import java.awt.image.*;
/** /**
* Resamples (scales) a {@code BufferedImage} to a new width and height, using * Resamples (scales) a {@code BufferedImage} to a new width and height, using
* high performance and high quality algorithms. * high performance and high quality algorithms.
@@ -138,7 +137,7 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
// MagickAccelerator to work consistently (see magick.FilterType). // MagickAccelerator to work consistently (see magick.FilterType).
/** /**
* Undefined interpolation, filter method will use default filter * Undefined interpolation, filter method will use default filter.
*/ */
public final static int FILTER_UNDEFINED = 0; public final static int FILTER_UNDEFINED = 0;
/** /**
@@ -194,11 +193,11 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
/** /**
* Mitchell interpolation. High quality. * Mitchell interpolation. High quality.
*/ */
public final static int FILTER_MITCHELL = 12;// IM default scale with palette or alpha, or scale up public final static int FILTER_MITCHELL = 12; // IM default scale with palette or alpha, or scale up
/** /**
* Lanczos interpolation. High quality. * Lanczos interpolation. High quality.
*/ */
public final static int FILTER_LANCZOS = 13;// IM default public final static int FILTER_LANCZOS = 13; // IM default
/** /**
* Blackman-Bessel interpolation. High quality. * Blackman-Bessel interpolation. High quality.
*/ */
@@ -291,10 +290,10 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
// Member variables // Member variables
// Package access, to allow access from MagickAccelerator // Package access, to allow access from MagickAccelerator
int mWidth; int width;
int mHeight; int height;
int mFilterType; int filterType;
private static final boolean TRANSFORM_OP_BICUBIC_SUPPORT = SystemUtil.isFieldAvailable(AffineTransformOp.class.getName(), "TYPE_BICUBIC"); private static final boolean TRANSFORM_OP_BICUBIC_SUPPORT = SystemUtil.isFieldAvailable(AffineTransformOp.class.getName(), "TYPE_BICUBIC");
/** /**
@@ -302,14 +301,13 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
*/ */
// TODO: Move to abstract class AbstractBufferedImageOp? // TODO: Move to abstract class AbstractBufferedImageOp?
static class Key extends RenderingHints.Key { static class Key extends RenderingHints.Key {
static int sIndex = 10000; static int sIndex = 10000;
private final String mName; private final String name;
public Key(final String pName) { public Key(final String pName) {
super(sIndex++); super(sIndex++);
mName = pName; name = pName;
} }
public boolean isCompatibleValue(Object pValue) { public boolean isCompatibleValue(Object pValue) {
@@ -317,7 +315,7 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
} }
public String toString() { public String toString() {
return mName; return name;
} }
} }
@@ -326,27 +324,27 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
*/ */
// TODO: Extract abstract Value class, and move to AbstractBufferedImageOp // TODO: Extract abstract Value class, and move to AbstractBufferedImageOp
static final class Value { static final class Value {
final private RenderingHints.Key mKey; final private RenderingHints.Key key;
final private String mName; final private String name;
final private int mType; final private int type;
public Value(final RenderingHints.Key pKey, final String pName, final int pType) { public Value(final RenderingHints.Key pKey, final String pName, final int pType) {
mKey = pKey; key = pKey;
mName = pName; name = pName;
validateFilterType(pType); validateFilterType(pType);
mType = pType;// TODO: test for duplicates type = pType;// TODO: test for duplicates
} }
public boolean isCompatibleKey(Key pKey) { public boolean isCompatibleKey(Key pKey) {
return pKey == mKey; return pKey == key;
} }
public int getFilterType() { public int getFilterType() {
return mType; return type;
} }
public String toString() { public String toString() {
return mName; return name;
} }
} }
@@ -354,11 +352,11 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
* Creates a {@code ResampleOp} that will resample input images to the * Creates a {@code ResampleOp} that will resample input images to the
* given width and height, using the default interpolation filter. * given width and height, using the default interpolation filter.
* *
* @param pWidth width of the resampled image * @param width width of the re-sampled image
* @param pHeight height of the resampled image * @param height height of the re-sampled image
*/ */
public ResampleOp(int pWidth, int pHeight) { public ResampleOp(int width, int height) {
this(pWidth, pHeight, FILTER_UNDEFINED); this(width, height, FILTER_UNDEFINED);
} }
/** /**
@@ -394,38 +392,38 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
* </ul> * </ul>
* Other hints have no effect on this filter. * Other hints have no effect on this filter.
* *
* @param pWidth width of the resampled image * @param width width of the re-sampled image
* @param pHeight height of the resampled image * @param height height of the re-sampled image
* @param pHints rendering hints, affecting interpolation algorithm * @param hints rendering hints, affecting interpolation algorithm
* @see #KEY_RESAMPLE_INTERPOLATION * @see #KEY_RESAMPLE_INTERPOLATION
* @see RenderingHints#KEY_INTERPOLATION * @see RenderingHints#KEY_INTERPOLATION
* @see RenderingHints#KEY_RENDERING * @see RenderingHints#KEY_RENDERING
* @see RenderingHints#KEY_COLOR_RENDERING * @see RenderingHints#KEY_COLOR_RENDERING
*/ */
public ResampleOp(int pWidth, int pHeight, RenderingHints pHints) { public ResampleOp(int width, int height, RenderingHints hints) {
this(pWidth, pHeight, getFilterType(pHints)); this(width, height, getFilterType(hints));
} }
/** /**
* Creates a {@code ResampleOp} that will resample input images to the * Creates a {@code ResampleOp} that will resample input images to the
* given width and height, using the given interpolation filter. * given width and height, using the given interpolation filter.
* *
* @param pWidth width of the resampled image * @param width width of the re-sampled image
* @param pHeight height of the resampled image * @param height height of the re-sampled image
* @param pFilterType interpolation filter algorithm * @param filterType interpolation filter algorithm
* @see <a href="#field_summary">filter type constants</a> * @see <a href="#field_summary">filter type constants</a>
*/ */
public ResampleOp(int pWidth, int pHeight, int pFilterType) { public ResampleOp(int width, int height, int filterType) {
if (pWidth <= 0 || pHeight <= 0) { if (width <= 0 || height <= 0) {
// NOTE: w/h == 0 makes the Magick DLL crash and the JVM dies.. :-P // NOTE: w/h == 0 makes the Magick DLL crash and the JVM dies.. :-P
throw new IllegalArgumentException("width and height must be positive"); throw new IllegalArgumentException("width and height must be positive");
} }
mWidth = pWidth; this.width = width;
mHeight = pHeight; this.height = height;
validateFilterType(pFilterType); validateFilterType(filterType);
mFilterType = pFilterType; this.filterType = filterType;
} }
private static void validateFilterType(int pFilterType) { private static void validateFilterType(int pFilterType) {
@@ -471,25 +469,21 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
} }
return value != null ? ((Value) value).getFilterType() : FILTER_UNDEFINED; return value != null ? ((Value) value).getFilterType() : FILTER_UNDEFINED;
} }
else else if (RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR.equals(pHints.get(RenderingHints.KEY_INTERPOLATION))
if (RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR.equals(pHints.get(RenderingHints.KEY_INTERPOLATION))
|| (!pHints.containsKey(RenderingHints.KEY_INTERPOLATION) || (!pHints.containsKey(RenderingHints.KEY_INTERPOLATION)
&& (RenderingHints.VALUE_RENDER_SPEED.equals(pHints.get(RenderingHints.KEY_RENDERING)) && (RenderingHints.VALUE_RENDER_SPEED.equals(pHints.get(RenderingHints.KEY_RENDERING))
|| RenderingHints.VALUE_COLOR_RENDER_SPEED.equals(pHints.get(RenderingHints.KEY_COLOR_RENDERING))))) { || RenderingHints.VALUE_COLOR_RENDER_SPEED.equals(pHints.get(RenderingHints.KEY_COLOR_RENDERING))))) {
// Nearest neighbour, or prioritze speed // Nearest neighbour, or prioritize speed
return FILTER_POINT; return FILTER_POINT;
} }
else else if (RenderingHints.VALUE_INTERPOLATION_BILINEAR.equals(pHints.get(RenderingHints.KEY_INTERPOLATION))) {
if (RenderingHints.VALUE_INTERPOLATION_BILINEAR.equals(pHints.get(RenderingHints.KEY_INTERPOLATION))) {
// Triangle equals bi-linear interpolation // Triangle equals bi-linear interpolation
return FILTER_TRIANGLE; return FILTER_TRIANGLE;
} }
else else if (RenderingHints.VALUE_INTERPOLATION_BICUBIC.equals(pHints.get(RenderingHints.KEY_INTERPOLATION))) {
if (RenderingHints.VALUE_INTERPOLATION_BICUBIC.equals(pHints.get(RenderingHints.KEY_INTERPOLATION))) {
return FILTER_QUADRATIC;// No idea if this is correct..? return FILTER_QUADRATIC;// No idea if this is correct..?
} }
else else if (RenderingHints.VALUE_RENDER_QUALITY.equals(pHints.get(RenderingHints.KEY_RENDERING))
if (RenderingHints.VALUE_RENDER_QUALITY.equals(pHints.get(RenderingHints.KEY_RENDERING))
|| RenderingHints.VALUE_COLOR_RENDER_QUALITY.equals(pHints.get(RenderingHints.KEY_COLOR_RENDERING))) { || RenderingHints.VALUE_COLOR_RENDER_QUALITY.equals(pHints.get(RenderingHints.KEY_COLOR_RENDERING))) {
// Prioritize quality // Prioritize quality
return FILTER_MITCHELL; return FILTER_MITCHELL;
@@ -500,83 +494,88 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
} }
/** /**
* Resamples (scales) the image to the size, and using the algorithm * Re-samples (scales) the image to the size, and using the algorithm
* specified in the constructor. * specified in the constructor.
* *
* @param pInput The {@code BufferedImage} to be filtered * @param input The {@code BufferedImage} to be filtered
* @param pOutput The {@code BufferedImage} in which to store the resampled * @param output The {@code BufferedImage} in which to store the resampled
* image * image
* @return The resampled {@code BufferedImage}. * @return The re-sampled {@code BufferedImage}.
* @throws NullPointerException if {@code pInput} is {@code null} * @throws NullPointerException if {@code input} is {@code null}
* @throws IllegalArgumentException if {@code pInput == pOutput}. * @throws IllegalArgumentException if {@code input == output}.
* @see #ResampleOp(int,int,int) * @see #ResampleOp(int,int,int)
*/ */
public final BufferedImage filter(final BufferedImage pInput, final BufferedImage pOutput) { public final BufferedImage filter(final BufferedImage input, final BufferedImage output) {
if (pInput == null) { if (input == null) {
throw new NullPointerException("Input == null"); throw new NullPointerException("Input == null");
} }
if (pInput == pOutput) { if (input == output) {
throw new IllegalArgumentException("Output image cannot be the same as the input image"); throw new IllegalArgumentException("Output image cannot be the same as the input image");
} }
InterpolationFilter filter; InterpolationFilter filter;
// Special case for POINT, TRIANGLE and QUADRATIC filter, as standard // Special case for POINT, TRIANGLE and QUADRATIC filter, as standard
// Java implementation is very fast (possibly H/W accellerated) // Java implementation is very fast (possibly H/W accelerated)
switch (mFilterType) { switch (filterType) {
case FILTER_POINT: case FILTER_POINT:
return fastResample(pInput, pOutput, mWidth, mHeight, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); if (input.getType() != BufferedImage.TYPE_CUSTOM) {
case FILTER_TRIANGLE: return fastResample(input, output, width, height, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
return fastResample(pInput, pOutput, mWidth, mHeight, AffineTransformOp.TYPE_BILINEAR);
case FILTER_QUADRATIC:
if (TRANSFORM_OP_BICUBIC_SUPPORT) {
return fastResample(pInput, pOutput, mWidth, mHeight, 3); // AffineTransformOp.TYPE_BICUBIC
} }
// Fall through // Else fall through
case FILTER_TRIANGLE:
if (input.getType() != BufferedImage.TYPE_CUSTOM) {
return fastResample(input, output, width, height, AffineTransformOp.TYPE_BILINEAR);
}
// Else fall through
case FILTER_QUADRATIC:
if (input.getType() != BufferedImage.TYPE_CUSTOM && TRANSFORM_OP_BICUBIC_SUPPORT) {
return fastResample(input, output, width, height, 3); // AffineTransformOp.TYPE_BICUBIC
}
// Else fall through
default: default:
filter = createFilter(mFilterType); filter = createFilter(filterType);
// NOTE: Workaround for filter throwing exceptions when input or output is less than support... // NOTE: Workaround for filter throwing exceptions when input or output is less than support...
if (Math.min(pInput.getWidth(), pInput.getHeight()) <= filter.support() || Math.min(mWidth, mHeight) <= filter.support()) { if (Math.min(input.getWidth(), input.getHeight()) <= filter.support() || Math.min(width, height) <= filter.support()) {
return fastResample(pInput, pOutput, mWidth, mHeight, AffineTransformOp.TYPE_BILINEAR); return fastResample(input, output, width, height, AffineTransformOp.TYPE_BILINEAR);
} }
// Fall through // Fall through
} }
// Try to use native ImageMagick code // Try to use native ImageMagick code
BufferedImage result = MagickAccelerator.filter(this, pInput, pOutput); BufferedImage result = MagickAccelerator.filter(this, input, output);
if (result != null) { if (result != null) {
return result; return result;
} }
// Otherwise, continue in pure Java mode // Otherwise, continue in pure Java mode
// TODO: What if pOutput != null and wrong size? Create new? Render on only a part? Document? // TODO: What if output != null and wrong size? Create new? Render on only a part? Document?
// If filter type != POINT or BOX an input has IndexColorModel, convert // If filter type != POINT or BOX an input has IndexColorModel, convert
// to true color, with alpha reflecting that of the original colormodel. // to true color, with alpha reflecting that of the original color model.
BufferedImage input; BufferedImage temp;
ColorModel cm; ColorModel cm;
if (mFilterType != FILTER_BOX && (cm = pInput.getColorModel()) instanceof IndexColorModel) { if (filterType != FILTER_POINT && filterType != FILTER_BOX && (cm = input.getColorModel()) instanceof IndexColorModel) {
// TODO: OPTIMIZE: If colormodel has only b/w or gray, we could skip color info // TODO: OPTIMIZE: If color model has only b/w or gray, we could skip color info
input = ImageUtil.toBuffered(pInput, cm.hasAlpha() ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR); temp = ImageUtil.toBuffered(input, cm.hasAlpha() ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR);
} }
else { else {
input = pInput; temp = input;
} }
// Create or convert output to a suitable image // Create or convert output to a suitable image
// TODO: OPTIMIZE: Don't really need to convert all types to same as input // TODO: OPTIMIZE: Don't really need to convert all types to same as input
result = pOutput != null ? /*pOutput*/ ImageUtil.toBuffered(pOutput, input.getType()) : createCompatibleDestImage(input, null); result = output != null && temp.getType() != BufferedImage.TYPE_CUSTOM ? /*output*/ ImageUtil.toBuffered(output, temp.getType()) : createCompatibleDestImage(temp, null);
// result = output != null ? output : createCompatibleDestImage(temp, null);
resample(input, result, filter); resample(temp, result, filter);
// If pOutput != null and needed to be converted, draw it back // If output != null and needed to be converted, draw it back
if (pOutput != null && pOutput != result) { if (output != null && output != result) {
//pOutput.setData(output.getRaster()); //output.setData(output.getRaster());
ImageUtil.drawOnto(pOutput, result); ImageUtil.drawOnto(output, result);
result = pOutput; result = output;
} }
return result; return result;
@@ -672,8 +671,8 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
} }
*/ */
private static BufferedImage fastResample(final BufferedImage pInput, final BufferedImage pOutput, final int pWidth, final int pHeight, final int pType) { private static BufferedImage fastResample(final BufferedImage input, final BufferedImage output, final int width, final int height, final int type) {
BufferedImage temp = pInput; BufferedImage temp = input;
double xScale; double xScale;
double yScale; double yScale;
@@ -681,20 +680,20 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
AffineTransform transform; AffineTransform transform;
AffineTransformOp scale; AffineTransformOp scale;
if (pType > AffineTransformOp.TYPE_NEAREST_NEIGHBOR) { if (type > AffineTransformOp.TYPE_NEAREST_NEIGHBOR) {
// Initially scale so all remaining operations will halve the image // Initially scale so all remaining operations will halve the image
if (pWidth < pInput.getWidth() || pHeight < pInput.getHeight()) { if (width < input.getWidth() || height < input.getHeight()) {
int w = pWidth; int w = width;
int h = pHeight; int h = height;
while (w < pInput.getWidth() / 2) { while (w < input.getWidth() / 2) {
w *= 2; w *= 2;
} }
while (h < pInput.getHeight() / 2) { while (h < input.getHeight() / 2) {
h *= 2; h *= 2;
} }
xScale = w / (double) pInput.getWidth(); xScale = w / (double) input.getWidth();
yScale = h / (double) pInput.getHeight(); yScale = h / (double) input.getHeight();
//System.out.println("First scale by x=" + xScale + ", y=" + yScale); //System.out.println("First scale by x=" + xScale + ", y=" + yScale);
@@ -704,12 +703,12 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
} }
} }
scale = null;// NOTE: This resets! scale = null; // NOTE: This resets!
xScale = pWidth / (double) temp.getWidth(); xScale = width / (double) temp.getWidth();
yScale = pHeight / (double) temp.getHeight(); yScale = height / (double) temp.getHeight();
if (pType > AffineTransformOp.TYPE_NEAREST_NEIGHBOR) { if (type > AffineTransformOp.TYPE_NEAREST_NEIGHBOR) {
// TODO: Test skipping first scale (above), and instead scale once // TODO: Test skipping first scale (above), and instead scale once
// more here, and a little less than .5 each time... // more here, and a little less than .5 each time...
// That would probably make the scaling smoother... // That would probably make the scaling smoother...
@@ -740,17 +739,15 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
} }
temp = scale.filter(temp, null); temp = scale.filter(temp, null);
} }
} }
//System.out.println("Rest to scale by x=" + xScale + ", y=" + yScale); //System.out.println("Rest to scale by x=" + xScale + ", y=" + yScale);
transform = AffineTransform.getScaleInstance(xScale, yScale); transform = AffineTransform.getScaleInstance(xScale, yScale);
scale = new AffineTransformOp(transform, pType); scale = new AffineTransformOp(transform, type);
return scale.filter(temp, pOutput);
return scale.filter(temp, output);
} }
/** /**
@@ -760,7 +757,7 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
* @see <a href="#field_summary">filter type constants</a> * @see <a href="#field_summary">filter type constants</a>
*/ */
public int getFilterType() { public int getFilterType() {
return mFilterType; return filterType;
} }
private static InterpolationFilter createFilter(int pFilterType) { private static InterpolationFilter createFilter(int pFilterType) {
@@ -770,7 +767,8 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
} }
switch (pFilterType) { switch (pFilterType) {
//case FILTER_POINT: // Should never happen case FILTER_POINT:
return new PointFilter();
case FILTER_BOX: case FILTER_BOX:
return new BoxFilter(); return new BoxFilter();
case FILTER_TRIANGLE: case FILTER_TRIANGLE:
@@ -815,14 +813,14 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
// If indexcolormodel, we probably don't want to use that... // If indexcolormodel, we probably don't want to use that...
// NOTE: Either BOTH or NONE of the images must have ALPHA // NOTE: Either BOTH or NONE of the images must have ALPHA
return new BufferedImage(cm, ImageUtil.createCompatibleWritableRaster(pInput, cm, mWidth, mHeight), return new BufferedImage(cm, ImageUtil.createCompatibleWritableRaster(pInput, cm, width, height),
cm.isAlphaPremultiplied(), null); cm.isAlphaPremultiplied(), null);
} }
public RenderingHints getRenderingHints() { public RenderingHints getRenderingHints() {
Object value; Object value;
switch (mFilterType) { switch (filterType) {
case FILTER_UNDEFINED: case FILTER_UNDEFINED:
return null; return null;
case FILTER_POINT: case FILTER_POINT:
@@ -871,14 +869,14 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
value = VALUE_INTERPOLATION_BLACKMAN_SINC; value = VALUE_INTERPOLATION_BLACKMAN_SINC;
break; break;
default: default:
throw new IllegalStateException("Unknown filter type: " + mFilterType); throw new IllegalStateException("Unknown filter type: " + filterType);
} }
return new RenderingHints(KEY_RESAMPLE_INTERPOLATION, value); return new RenderingHints(KEY_RESAMPLE_INTERPOLATION, value);
} }
public Rectangle2D getBounds2D(BufferedImage src) { public Rectangle2D getBounds2D(BufferedImage src) {
return new Rectangle(mWidth, mHeight); return new Rectangle(width, height);
} }
public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
@@ -1439,10 +1437,8 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
resample() resample()
Resizes bitmaps while resampling them. Resizes bitmaps while resampling them.
Returns -1 if error, 0 if success.
*/ */
private BufferedImage resample(BufferedImage pSource, BufferedImage pDest, InterpolationFilter pFilter) { private BufferedImage resample(BufferedImage pSource, BufferedImage pDest, InterpolationFilter pFilter) {
// TODO: Don't work... Could fix by creating a temporary image in filter method
final int dstWidth = pDest.getWidth(); final int dstWidth = pDest.getWidth();
final int dstHeight = pDest.getHeight(); final int dstHeight = pDest.getHeight();
@@ -1451,7 +1447,8 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
/* create intermediate column to hold horizontal dst column zoom */ /* create intermediate column to hold horizontal dst column zoom */
final ColorModel cm = pSource.getColorModel(); final ColorModel cm = pSource.getColorModel();
final WritableRaster work = cm.createCompatibleWritableRaster(1, srcHeight); // final WritableRaster work = cm.createCompatibleWritableRaster(1, srcHeight);
final WritableRaster work = ImageUtil.createCompatibleWritableRaster(pSource, cm, 1, srcHeight);
double xscale = (double) dstWidth / (double) srcWidth; double xscale = (double) dstWidth / (double) srcWidth;
double yscale = (double) dstHeight / (double) srcHeight; double yscale = (double) dstHeight / (double) srcHeight;
@@ -1566,7 +1563,7 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
final WritableRaster out = pDest.getRaster(); final WritableRaster out = pDest.getRaster();
// TODO: This is not optimal for non-byte-packed rasters... // TODO: This is not optimal for non-byte-packed rasters...
// (What? Maybe I implemented the fix, but forgot to remove the qTODO?) // (What? Maybe I implemented the fix, but forgot to remove the TODO?)
final int numChannels = raster.getNumBands(); final int numChannels = raster.getNumBands();
final int[] channelMax = new int[numChannels]; final int[] channelMax = new int[numChannels];
for (int k = 0; k < numChannels; k++) { for (int k = 0; k < numChannels; k++) {
@@ -1575,7 +1572,7 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
for (int xx = 0; xx < dstWidth; xx++) { for (int xx = 0; xx < dstWidth; xx++) {
ContributorList contribX = calcXContrib(xscale, fwidth, srcWidth, pFilter, xx); ContributorList contribX = calcXContrib(xscale, fwidth, srcWidth, pFilter, xx);
/* Apply horz filter to make dst column in tmp. */ /* Apply horiz filter to make dst column in tmp. */
for (int k = 0; k < srcHeight; k++) { for (int k = 0; k < srcHeight; k++) {
for (int channel = 0; channel < numChannels; channel++) { for (int channel = 0; channel < numChannels; channel++) {

View File

@@ -42,8 +42,8 @@ import java.awt.image.ReplicateScaleFilter;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/SubsamplingFilter.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/SubsamplingFilter.java#1 $
*/ */
public class SubsamplingFilter extends ReplicateScaleFilter { public class SubsamplingFilter extends ReplicateScaleFilter {
private int mXSub; private int xSub;
private int mYSub; private int ySub;
/** /**
* Creates a {@code SubsamplingFilter}. * Creates a {@code SubsamplingFilter}.
@@ -62,16 +62,16 @@ public class SubsamplingFilter extends ReplicateScaleFilter {
throw new IllegalArgumentException("Subsampling factors must be positive."); throw new IllegalArgumentException("Subsampling factors must be positive.");
} }
mXSub = pXSub; xSub = pXSub;
mYSub = pYSub; ySub = pYSub;
} }
/** {@code ImageFilter} implementation, do not invoke. */ /** {@code ImageFilter} implementation, do not invoke. */
public void setDimensions(int pWidth, int pHeight) { public void setDimensions(int pWidth, int pHeight) {
destWidth = (pWidth + mXSub - 1) / mXSub; destWidth = (pWidth + xSub - 1) / xSub;
destHeight = (pHeight + mYSub - 1) / mYSub; destHeight = (pHeight + ySub - 1) / ySub;
//System.out.println("Subsampling: " + mXSub + "," + mYSub + "-> " + destWidth + ", " + destHeight); //System.out.println("Subsampling: " + xSub + "," + ySub + "-> " + destWidth + ", " + destHeight);
super.setDimensions(pWidth, pHeight); super.setDimensions(pWidth, pHeight);
} }
} }

View File

@@ -4,6 +4,6 @@
* See the class {@link com.twelvemonkeys.image.ImageUtil}. * See the class {@link com.twelvemonkeys.image.ImageUtil}.
* *
* @version 1.0 * @version 1.0
* @author <a href="mailto:harald@escenic.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
*/ */
package com.twelvemonkeys.image; package com.twelvemonkeys.image;

View File

@@ -0,0 +1,206 @@
package com.twelvemonkeys.image;
import org.junit.Test;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ImageProducer;
import java.net.URL;
import static org.junit.Assert.*;
/**
* BufferedImageFactoryTestCase
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: BufferedImageFactoryTestCase.java,v 1.0 May 7, 2010 12:40:08 PM haraldk Exp$
*/
public class BufferedImageFactoryTestCase {
@Test(expected = IllegalArgumentException.class)
public void testCreateNullImage() {
new BufferedImageFactory((Image) null);
}
@Test(expected = IllegalArgumentException.class)
public void testCreateNullProducer() {
new BufferedImageFactory((ImageProducer) null);
}
// Image source = Toolkit.getDefaultToolkit().createImage((byte[]) null); // - NPE in Toolkit, ok
@Test(timeout = 1000, expected = IllegalArgumentException.class)
public void testGetBufferedImageErrorSourceIP() {
Image source = Toolkit.getDefaultToolkit().createImage((ImageProducer) null);
new BufferedImageFactory(source);
}
// TODO: This is a quite serious bug, but it can be argued that the bug is in the
// Toolkit, allowing such images in the first place... In any case, there's
// not much we can do, except until someone is bored and kills the app... :-P
/*
@Test(timeout = 1000, expected = ImageConversionException.class)
public void testGetBufferedImageErrorSourceString() {
Image source = Toolkit.getDefaultToolkit().createImage((String) null);
BufferedImageFactory factory = new BufferedImageFactory(source);
factory.getBufferedImage();
}
*/
// This is a little random, and it would be nicer if we could throw an IllegalArgumentException on create.
// Unfortunately, the API doesn't allow this...
@Test(timeout = 1000, expected = ImageConversionException.class)
public void testGetBufferedImageErrorSourceURL() {
Image source = Toolkit.getDefaultToolkit().createImage(getClass().getResource("/META-INF/MANIFEST.MF"));
BufferedImageFactory factory = new BufferedImageFactory(source);
factory.getBufferedImage();
}
@Test
public void testGetBufferedImageJPEG() {
URL resource = getClass().getResource("/sunflower.jpg");
assertNotNull(resource);
Image source = Toolkit.getDefaultToolkit().createImage(resource);
assertNotNull(source);
BufferedImageFactory factory = new BufferedImageFactory(source);
BufferedImage image = factory.getBufferedImage();
assertEquals(187, image.getWidth());
assertEquals(283, image.getHeight());
}
@Test
public void testGetColorModelJPEG() {
URL resource = getClass().getResource("/sunflower.jpg");
assertNotNull(resource);
Image source = Toolkit.getDefaultToolkit().createImage(resource);
assertNotNull(source);
BufferedImageFactory factory = new BufferedImageFactory(source);
ColorModel colorModel = factory.getColorModel();
assertNotNull(colorModel);
assertEquals(3, colorModel.getNumColorComponents()); // getNumComponents may include alpha, we don't care
assertEquals(ColorSpace.getInstance(ColorSpace.CS_sRGB), colorModel.getColorSpace());
for (int i = 0; i < colorModel.getNumComponents(); i++) {
assertEquals(8, colorModel.getComponentSize(i));
}
}
// TODO: Test a GIF or PNG with PLTE chunk, and make sure we get an IndexColorModel
@Test
public void testGetBufferedImageSubsampled() {
URL resource = getClass().getResource("/sunflower.jpg");
assertNotNull(resource);
Image source = Toolkit.getDefaultToolkit().createImage(resource);
assertNotNull(source);
BufferedImageFactory factory = new BufferedImageFactory(source);
BufferedImage original = factory.getBufferedImage();
factory.setSourceSubsampling(2, 2);
BufferedImage image = factory.getBufferedImage(); // Accidentally also tests reuse...
// Values rounded up
assertEquals(94, image.getWidth());
assertEquals(142, image.getHeight());
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
assertEquals("RGB[" + x + ", " + y + "]", original.getRGB(x * 2, y * 2), image.getRGB(x, y));
}
}
}
@Test
public void testGetBufferedImageSourceRegion() {
URL resource = getClass().getResource("/sunflower.jpg");
assertNotNull(resource);
Image source = Toolkit.getDefaultToolkit().createImage(resource);
assertNotNull(source);
BufferedImageFactory factory = new BufferedImageFactory(source);
BufferedImage original = factory.getBufferedImage();
factory.setSourceRegion(new Rectangle(40, 40, 40, 40));
BufferedImage image = factory.getBufferedImage(); // Accidentally also tests reuse...
assertEquals(40, image.getWidth());
assertEquals(40, image.getHeight());
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
assertEquals("RGB[" + x + ", " + y + "]", original.getRGB(40 + x, 40 + y), image.getRGB(x, y));
}
}
}
@Test
public void testGetBufferedImageSubsampledSourceRegion() throws Exception{
URL resource = getClass().getResource("/sunflower.jpg");
assertNotNull(resource);
Image source = Toolkit.getDefaultToolkit().createImage(resource);
assertNotNull(source);
BufferedImageFactory factory = new BufferedImageFactory(source);
BufferedImage original = factory.getBufferedImage();
factory.setSourceRegion(new Rectangle(40, 40, 40, 40));
factory.setSourceSubsampling(2, 2);
BufferedImage image = factory.getBufferedImage(); // Accidentally also tests reuse...
assertEquals(20, image.getWidth());
assertEquals(20, image.getHeight());
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
assertEquals("RGB[" + x + ", " + y + "]", original.getRGB(40 + x * 2, 40 + y * 2), image.getRGB(x, y));
}
}
}
@Test
public void testListener() {
URL resource = getClass().getResource("/sunflower.jpg");
assertNotNull(resource);
Image source = Toolkit.getDefaultToolkit().createImage(resource);
assertNotNull(source);
BufferedImageFactory factory = new BufferedImageFactory(source);
VerifyingListener listener = new VerifyingListener(factory);
factory.addProgressListener(listener);
factory.getBufferedImage();
listener.verify();
}
private static class VerifyingListener implements BufferedImageFactory.ProgressListener {
private final BufferedImageFactory factory;
private float progress;
public VerifyingListener(BufferedImageFactory factory) {
this.factory = factory;
}
public void progress(BufferedImageFactory pFactory, float pPercentage) {
assertEquals(factory, pFactory);
assertTrue(pPercentage >= progress && pPercentage <= 100f);
progress = pPercentage;
}
public void verify() {
assertEquals(100f, progress, .1f); // Sanity test that the listener was invoked
}
}
}

View File

@@ -24,35 +24,35 @@ import java.lang.reflect.InvocationTargetException;
public class ImageUtilTestCase extends TestCase { public class ImageUtilTestCase extends TestCase {
private final static String IMAGE_NAME = "/sunflower.jpg"; private final static String IMAGE_NAME = "/sunflower.jpg";
private BufferedImage mOriginal; private BufferedImage original;
private BufferedImage mImage; private BufferedImage image;
private Image mScaled; private Image scaled;
public ImageUtilTestCase() throws Exception { public ImageUtilTestCase() throws Exception {
mImage = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB); image = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
mScaled = mImage.getScaledInstance(5, 5, Image.SCALE_FAST); scaled = image.getScaledInstance(5, 5, Image.SCALE_FAST);
// Read image from class path // Read image from class path
InputStream is = getClass().getResourceAsStream(IMAGE_NAME); InputStream is = getClass().getResourceAsStream(IMAGE_NAME);
mOriginal = ImageIO.read(is); original = ImageIO.read(is);
assertNotNull(mOriginal); assertNotNull(original);
} }
/* /*
public void setUp() throws Exception { public void setUp() throws Exception {
mImage = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB); image = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
mScaled = mImage.getScaledInstance(5, 5, Image.SCALE_FAST); scaled = image.getScaledInstance(5, 5, Image.SCALE_FAST);
// Read image from class path // Read image from class path
InputStream is = ClassLoader.getSystemResourceAsStream(IMAGE_NAME); InputStream is = ClassLoader.getSystemResourceAsStream(IMAGE_NAME);
mOriginal = ImageIO.read(is); original = ImageIO.read(is);
assertNotNull(mOriginal); assertNotNull(original);
} }
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
mOriginal = null; original = null;
} }
*/ */
@@ -94,20 +94,20 @@ public class ImageUtilTestCase extends TestCase {
// Should not be a buffered image // Should not be a buffered image
assertFalse( assertFalse(
"FOR SOME IMPLEMENTATIONS THIS MIGHT FAIL!\nIn that case, testToBufferedImage() will fail too.", "FOR SOME IMPLEMENTATIONS THIS MIGHT FAIL!\nIn that case, testToBufferedImage() will fail too.",
mScaled instanceof BufferedImage scaled instanceof BufferedImage
); );
} }
public void testToBufferedImage() { public void testToBufferedImage() {
BufferedImage sameAsImage = ImageUtil.toBuffered((RenderedImage) mImage); BufferedImage sameAsImage = ImageUtil.toBuffered((RenderedImage) image);
BufferedImage bufferedScaled = ImageUtil.toBuffered(mScaled); BufferedImage bufferedScaled = ImageUtil.toBuffered(scaled);
// Should be no need to convert // Should be no need to convert
assertSame(mImage, sameAsImage); assertSame(image, sameAsImage);
// Should have same dimensions // Should have same dimensions
assertEquals(mScaled.getWidth(null), bufferedScaled.getWidth()); assertEquals(scaled.getWidth(null), bufferedScaled.getWidth());
assertEquals(mScaled.getHeight(null), bufferedScaled.getHeight()); assertEquals(scaled.getHeight(null), bufferedScaled.getHeight());
// Hmmm... // Hmmm...
assertTrue(new Integer(42).equals(bufferedScaled.getProperty("lucky-number")) assertTrue(new Integer(42).equals(bufferedScaled.getProperty("lucky-number"))
@@ -116,28 +116,28 @@ public class ImageUtilTestCase extends TestCase {
} }
public void testToBufferedImageType() { public void testToBufferedImageType() {
// Assumes mImage is TYPE_INT_ARGB // Assumes image is TYPE_INT_ARGB
BufferedImage converted = ImageUtil.toBuffered(mImage, BufferedImage.TYPE_BYTE_INDEXED); BufferedImage converted = ImageUtil.toBuffered(image, BufferedImage.TYPE_BYTE_INDEXED);
BufferedImage convertedToo = ImageUtil.toBuffered(mImage, BufferedImage.TYPE_BYTE_BINARY); BufferedImage convertedToo = ImageUtil.toBuffered(image, BufferedImage.TYPE_BYTE_BINARY);
// Should not be the same // Should not be the same
assertNotSame(mImage, converted); assertNotSame(image, converted);
assertNotSame(mImage, convertedToo); assertNotSame(image, convertedToo);
// Correct type // Correct type
assertTrue(converted.getType() == BufferedImage.TYPE_BYTE_INDEXED); assertTrue(converted.getType() == BufferedImage.TYPE_BYTE_INDEXED);
assertTrue(convertedToo.getType() == BufferedImage.TYPE_BYTE_BINARY); assertTrue(convertedToo.getType() == BufferedImage.TYPE_BYTE_BINARY);
// Should have same dimensions // Should have same dimensions
assertEquals(mImage.getWidth(), converted.getWidth()); assertEquals(image.getWidth(), converted.getWidth());
assertEquals(mImage.getHeight(), converted.getHeight()); assertEquals(image.getHeight(), converted.getHeight());
assertEquals(mImage.getWidth(), convertedToo.getWidth()); assertEquals(image.getWidth(), convertedToo.getWidth());
assertEquals(mImage.getHeight(), convertedToo.getHeight()); assertEquals(image.getHeight(), convertedToo.getHeight());
} }
public void testBrightness() { public void testBrightness() {
final BufferedImage original = mOriginal; final BufferedImage original = this.original;
assertNotNull(original); assertNotNull(original);
final BufferedImage notBrightened = ImageUtil.toBuffered(ImageUtil.brightness(original, 0f)); final BufferedImage notBrightened = ImageUtil.toBuffered(ImageUtil.brightness(original, 0f));
@@ -217,7 +217,7 @@ public class ImageUtilTestCase extends TestCase {
public void testContrast() { public void testContrast() {
final BufferedImage original = mOriginal; final BufferedImage original = this.original;
assertNotNull(original); assertNotNull(original);
@@ -370,7 +370,7 @@ public class ImageUtilTestCase extends TestCase {
} }
public void testSharpen() { public void testSharpen() {
final BufferedImage original = mOriginal; final BufferedImage original = this.original;
assertNotNull(original); assertNotNull(original);
@@ -495,7 +495,7 @@ public class ImageUtilTestCase extends TestCase {
} }
public void testBlur() { public void testBlur() {
final BufferedImage original = mOriginal; final BufferedImage original = this.original;
assertNotNull(original); assertNotNull(original);
@@ -563,7 +563,7 @@ public class ImageUtilTestCase extends TestCase {
} }
public void testIndexImage() { public void testIndexImage() {
BufferedImage sunflower = mOriginal; BufferedImage sunflower = original;
assertNotNull(sunflower); assertNotNull(sunflower);

View File

@@ -14,28 +14,28 @@ import java.io.InputStream;
*/ */
abstract class AbstractCachedSeekableStream extends SeekableInputStream { abstract class AbstractCachedSeekableStream extends SeekableInputStream {
/** The backing stream */ /** The backing stream */
protected final InputStream mStream; protected final InputStream stream;
/** The stream positon in the backing stream (mStream) */ /** The stream positon in the backing stream (stream) */
protected long mStreamPosition; protected long streamPosition;
private StreamCache mCache; private StreamCache cache;
protected AbstractCachedSeekableStream(final InputStream pStream, final StreamCache pCache) { protected AbstractCachedSeekableStream(final InputStream pStream, final StreamCache pCache) {
Validate.notNull(pStream, "stream"); Validate.notNull(pStream, "stream");
Validate.notNull(pCache, "cache"); Validate.notNull(pCache, "cache");
mStream = pStream; stream = pStream;
mCache = pCache; cache = pCache;
} }
protected final StreamCache getCache() { protected final StreamCache getCache() {
return mCache; return cache;
} }
@Override @Override
public int available() throws IOException { public int available() throws IOException {
long avail = mStreamPosition - mPosition + mStream.available(); long avail = streamPosition - position + stream.available();
return avail > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) avail; return avail > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) avail;
} }
@@ -43,26 +43,26 @@ abstract class AbstractCachedSeekableStream extends SeekableInputStream {
checkOpen(); checkOpen();
int read; int read;
if (mPosition == mStreamPosition) { if (position == streamPosition) {
// TODO: Read more bytes here! // TODO: Read more bytes here!
// TODO: Use buffer if not in-memory cache? (See FileCacheSeekableStream overrides). // TODO: Use buffer if not in-memory cache? (See FileCacheSeekableStream overrides).
// Read a byte from the stream // Read a byte from the stream
read = mStream.read(); read = stream.read();
if (read >= 0) { if (read >= 0) {
mStreamPosition++; streamPosition++;
mCache.write(read); cache.write(read);
} }
} }
else { else {
// ..or read byte from the cache // ..or read byte from the cache
syncPosition(); syncPosition();
read = mCache.read(); read = cache.read();
} }
// TODO: This field is not REALLY considered accessible.. :-P // TODO: This field is not REALLY considered accessible.. :-P
if (read != -1) { if (read != -1) {
mPosition++; position++;
} }
return read; return read;
@@ -73,32 +73,32 @@ abstract class AbstractCachedSeekableStream extends SeekableInputStream {
checkOpen(); checkOpen();
int length; int length;
if (mPosition == mStreamPosition) { if (position == streamPosition) {
// Read bytes from the stream // Read bytes from the stream
length = mStream.read(pBytes, pOffset, pLength); length = stream.read(pBytes, pOffset, pLength);
if (length > 0) { if (length > 0) {
mStreamPosition += length; streamPosition += length;
mCache.write(pBytes, pOffset, length); cache.write(pBytes, pOffset, length);
} }
} }
else { else {
// ...or read bytes from the cache // ...or read bytes from the cache
syncPosition(); syncPosition();
length = mCache.read(pBytes, pOffset, pLength); length = cache.read(pBytes, pOffset, pLength);
} }
// TODO: This field is not REALLY considered accessible.. :-P // TODO: This field is not REALLY considered accessible.. :-P
if (length > 0) { if (length > 0) {
mPosition += length; position += length;
} }
return length; return length;
} }
protected final void syncPosition() throws IOException { protected final void syncPosition() throws IOException {
if (mCache.getPosition() != mPosition) { if (cache.getPosition() != position) {
mCache.seek(mPosition); // Assure EOF is correctly thrown cache.seek(position); // Assure EOF is correctly thrown
} }
} }
@@ -111,14 +111,14 @@ abstract class AbstractCachedSeekableStream extends SeekableInputStream {
public abstract boolean isCachedFile(); public abstract boolean isCachedFile();
protected void seekImpl(long pPosition) throws IOException { protected void seekImpl(long pPosition) throws IOException {
if (mStreamPosition < pPosition) { if (streamPosition < pPosition) {
// Make sure we append at end of cache // Make sure we append at end of cache
if (mCache.getPosition() != mStreamPosition) { if (cache.getPosition() != streamPosition) {
mCache.seek(mStreamPosition); cache.seek(streamPosition);
} }
// Read diff from stream into cache // Read diff from stream into cache
long left = pPosition - mStreamPosition; long left = pPosition - streamPosition;
// TODO: Use fixed buffer, instead of allocating here... // TODO: Use fixed buffer, instead of allocating here...
int bufferLen = left > 1024 ? 1024 : (int) left; int bufferLen = left > 1024 ? 1024 : (int) left;
@@ -126,11 +126,11 @@ abstract class AbstractCachedSeekableStream extends SeekableInputStream {
while (left > 0) { while (left > 0) {
int length = buffer.length < left ? buffer.length : (int) left; int length = buffer.length < left ? buffer.length : (int) left;
int read = mStream.read(buffer, 0, length); int read = stream.read(buffer, 0, length);
if (read > 0) { if (read > 0) {
mCache.write(buffer, 0, read); cache.write(buffer, 0, read);
mStreamPosition += read; streamPosition += read;
left -= read; left -= read;
} }
else if (read < 0) { else if (read < 0) {
@@ -138,27 +138,27 @@ abstract class AbstractCachedSeekableStream extends SeekableInputStream {
} }
} }
} }
else if (mStreamPosition >= pPosition) { else if (streamPosition >= pPosition) {
// Seek backwards into the cache // Seek backwards into the cache
mCache.seek(pPosition); cache.seek(pPosition);
} }
// System.out.println("pPosition: " + pPosition); // System.out.println("pPosition: " + pPosition);
// System.out.println("mPosition: " + mPosition); // System.out.println("position: " + position);
// System.out.println("mStreamPosition: " + mStreamPosition); // System.out.println("streamPosition: " + streamPosition);
// System.out.println("mCache.mPosition: " + mCache.getPosition()); // System.out.println("cache.position: " + cache.getPosition());
// NOTE: If mPosition == pPosition then we're good to go // NOTE: If position == pPosition then we're good to go
} }
protected void flushBeforeImpl(long pPosition) { protected void flushBeforeImpl(long pPosition) {
mCache.flush(pPosition); cache.flush(pPosition);
} }
protected void closeImpl() throws IOException { protected void closeImpl() throws IOException {
mCache.flush(mPosition); cache.flush(position);
mCache = null; cache = null;
mStream.close(); stream.close();
} }
/** /**

View File

@@ -46,15 +46,16 @@ import java.util.List;
*/ */
public class CompoundReader extends Reader { public class CompoundReader extends Reader {
private Reader mCurrent; private Reader current;
private List<Reader> mReaders; private List<Reader> readers;
protected final Object mLock;
protected final boolean mMarkSupported; protected final Object finalLock;
private int mCurrentReader; protected final boolean markSupported;
private int mMarkedReader;
private int mMark; private int currentReader;
private int markedReader;
private int mark;
private int mNext; private int mNext;
/** /**
@@ -71,10 +72,10 @@ public class CompoundReader extends Reader {
public CompoundReader(final Iterator<Reader> pReaders) { public CompoundReader(final Iterator<Reader> pReaders) {
super(Validate.notNull(pReaders, "readers")); super(Validate.notNull(pReaders, "readers"));
mLock = pReaders; // NOTE: It's ok to sync on pReaders, as the finalLock = pReaders; // NOTE: It's ok to sync on pReaders, as the
// reference can't change, only it's elements // reference can't change, only it's elements
mReaders = new ArrayList<Reader>(); readers = new ArrayList<Reader>();
boolean markSupported = true; boolean markSupported = true;
while (pReaders.hasNext()) { while (pReaders.hasNext()) {
@@ -82,25 +83,25 @@ public class CompoundReader extends Reader {
if (reader == null) { if (reader == null) {
throw new NullPointerException("readers cannot contain null-elements"); throw new NullPointerException("readers cannot contain null-elements");
} }
mReaders.add(reader); readers.add(reader);
markSupported = markSupported && reader.markSupported(); markSupported = markSupported && reader.markSupported();
} }
mMarkSupported = markSupported; this.markSupported = markSupported;
mCurrent = nextReader(); current = nextReader();
} }
protected final Reader nextReader() { protected final Reader nextReader() {
if (mCurrentReader >= mReaders.size()) { if (currentReader >= readers.size()) {
mCurrent = new EmptyReader(); current = new EmptyReader();
} }
else { else {
mCurrent = mReaders.get(mCurrentReader++); current = readers.get(currentReader++);
} }
// NOTE: Reset mNext for every reader, and record marked reader in mark/reset methods! // NOTE: Reset mNext for every reader, and record marked reader in mark/reset methods!
mNext = 0; mNext = 0;
return mCurrent; return current;
} }
/** /**
@@ -109,17 +110,18 @@ public class CompoundReader extends Reader {
* @throws IOException if the stream is closed * @throws IOException if the stream is closed
*/ */
protected final void ensureOpen() throws IOException { protected final void ensureOpen() throws IOException {
if (mReaders == null) { if (readers == null) {
throw new IOException("Stream closed"); throw new IOException("Stream closed");
} }
} }
public void close() throws IOException { public void close() throws IOException {
// Close all readers // Close all readers
for (Reader reader : mReaders) { for (Reader reader : readers) {
reader.close(); reader.close();
} }
mReaders = null;
readers = null;
} }
@Override @Override
@@ -130,46 +132,46 @@ public class CompoundReader extends Reader {
// TODO: It would be nice if we could actually close some readers now // TODO: It would be nice if we could actually close some readers now
synchronized (mLock) { synchronized (finalLock) {
ensureOpen(); ensureOpen();
mMark = mNext; mark = mNext;
mMarkedReader = mCurrentReader; markedReader = currentReader;
mCurrent.mark(pReadLimit); current.mark(pReadLimit);
} }
} }
@Override @Override
public void reset() throws IOException { public void reset() throws IOException {
synchronized (mLock) { synchronized (finalLock) {
ensureOpen(); ensureOpen();
if (mCurrentReader != mMarkedReader) { if (currentReader != markedReader) {
// Reset any reader before this // Reset any reader before this
for (int i = mCurrentReader; i >= mMarkedReader; i--) { for (int i = currentReader; i >= markedReader; i--) {
mReaders.get(i).reset(); readers.get(i).reset();
} }
mCurrentReader = mMarkedReader - 1; currentReader = markedReader - 1;
nextReader(); nextReader();
} }
mCurrent.reset(); current.reset();
mNext = mMark; mNext = mark;
} }
} }
@Override @Override
public boolean markSupported() { public boolean markSupported() {
return mMarkSupported; return markSupported;
} }
@Override @Override
public int read() throws IOException { public int read() throws IOException {
synchronized (mLock) { synchronized (finalLock) {
int read = mCurrent.read(); int read = current.read();
if (read < 0 && mCurrentReader < mReaders.size()) { if (read < 0 && currentReader < readers.size()) {
nextReader(); nextReader();
return read(); // In case of 0-length readers return read(); // In case of 0-length readers
} }
@@ -181,10 +183,10 @@ public class CompoundReader extends Reader {
} }
public int read(char pBuffer[], int pOffset, int pLength) throws IOException { public int read(char pBuffer[], int pOffset, int pLength) throws IOException {
synchronized (mLock) { synchronized (finalLock) {
int read = mCurrent.read(pBuffer, pOffset, pLength); int read = current.read(pBuffer, pOffset, pLength);
if (read < 0 && mCurrentReader < mReaders.size()) { if (read < 0 && currentReader < readers.size()) {
nextReader(); nextReader();
return read(pBuffer, pOffset, pLength); // In case of 0-length readers return read(pBuffer, pOffset, pLength); // In case of 0-length readers
} }
@@ -197,15 +199,15 @@ public class CompoundReader extends Reader {
@Override @Override
public boolean ready() throws IOException { public boolean ready() throws IOException {
return mCurrent.ready(); return current.ready();
} }
@Override @Override
public long skip(long pChars) throws IOException { public long skip(long pChars) throws IOException {
synchronized (mLock) { synchronized (finalLock) {
long skipped = mCurrent.skip(pChars); long skipped = current.skip(pChars);
if (skipped == 0 && mCurrentReader < mReaders.size()) { if (skipped == 0 && currentReader < readers.size()) {
nextReader(); nextReader();
return skip(pChars); // In case of 0-length readers return skip(pChars); // In case of 0-length readers
} }

View File

@@ -44,7 +44,7 @@ import java.io.ByteArrayInputStream;
// TODO: Performance test of a stream impl that uses list of fixed size blocks, rather than contiguous block // TODO: Performance test of a stream impl that uses list of fixed size blocks, rather than contiguous block
public final class FastByteArrayOutputStream extends ByteArrayOutputStream { public final class FastByteArrayOutputStream extends ByteArrayOutputStream {
/** Max grow size (unless if writing more than this amount of bytes) */ /** Max grow size (unless if writing more than this amount of bytes) */
protected int mMaxGrowSize = 1024 * 1024; // 1 MB protected int maxGrowSize = 1024 * 1024; // 1 MB
/** /**
* Creates a {@code ByteArrayOutputStream} with the given initial buffer * Creates a {@code ByteArrayOutputStream} with the given initial buffer
@@ -94,7 +94,7 @@ public final class FastByteArrayOutputStream extends ByteArrayOutputStream {
private void growIfNeeded(int pNewcount) { private void growIfNeeded(int pNewcount) {
if (pNewcount > buf.length) { if (pNewcount > buf.length) {
int newSize = Math.max(Math.min(buf.length << 1, buf.length + mMaxGrowSize), pNewcount); int newSize = Math.max(Math.min(buf.length << 1, buf.length + maxGrowSize), pNewcount);
byte newBuf[] = new byte[newSize]; byte newBuf[] = new byte[newSize];
System.arraycopy(buf, 0, newBuf, 0, count); System.arraycopy(buf, 0, newBuf, 0, count);
buf = newBuf; buf = newBuf;

View File

@@ -48,16 +48,7 @@ import java.io.*;
*/ */
public final class FileCacheSeekableStream extends AbstractCachedSeekableStream { public final class FileCacheSeekableStream extends AbstractCachedSeekableStream {
// private final InputStream mStream; private byte[] buffer;
// private final RandomAccessFile mCache;
private byte[] mBuffer;
/** The stream positon in the backing stream (mStream) */
// private long mStreamPosition;
// TODO: getStreamPosition() should always be the same as
// mCache.getFilePointer()
// otherwise there's some inconsistency here... Enforce this?
/** /**
* Creates a {@code FileCacheSeekableStream} reading from the given * Creates a {@code FileCacheSeekableStream} reading from the given
@@ -118,7 +109,7 @@ public final class FileCacheSeekableStream extends AbstractCachedSeekableStream
super(pStream, new FileCache(pFile)); super(pStream, new FileCache(pFile));
// TODO: Allow for custom buffer sizes? // TODO: Allow for custom buffer sizes?
mBuffer = new byte[1024]; buffer = new byte[1024];
} }
public final boolean isCachedMemory() { public final boolean isCachedMemory() {
@@ -132,39 +123,19 @@ public final class FileCacheSeekableStream extends AbstractCachedSeekableStream
@Override @Override
protected void closeImpl() throws IOException { protected void closeImpl() throws IOException {
super.closeImpl(); super.closeImpl();
mBuffer = null; buffer = null;
} }
/*
public final boolean isCached() {
return true;
}
// InputStream overrides
@Override
public int available() throws IOException {
long avail = mStreamPosition - mPosition + mStream.available();
return avail > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) avail;
}
public void closeImpl() throws IOException {
mStream.close();
mCache.close();
// TODO: Delete cache file here?
// ThreadPool.invokeLater(new DeleteFileAction(mCacheFile));
}
*/
@Override @Override
public int read() throws IOException { public int read() throws IOException {
checkOpen(); checkOpen();
int read; int read;
if (mPosition == mStreamPosition) { if (position == streamPosition) {
// Read ahead into buffer, for performance // Read ahead into buffer, for performance
read = readAhead(mBuffer, 0, mBuffer.length); read = readAhead(buffer, 0, buffer.length);
if (read >= 0) { if (read >= 0) {
read = mBuffer[0] & 0xff; read = buffer[0] & 0xff;
} }
//System.out.println("Read 1 byte from stream: " + Integer.toHexString(read & 0xff)); //System.out.println("Read 1 byte from stream: " + Integer.toHexString(read & 0xff));
@@ -179,7 +150,7 @@ public final class FileCacheSeekableStream extends AbstractCachedSeekableStream
// TODO: This field is not REALLY considered accessible.. :-P // TODO: This field is not REALLY considered accessible.. :-P
if (read != -1) { if (read != -1) {
mPosition++; position++;
} }
return read; return read;
} }
@@ -189,7 +160,7 @@ public final class FileCacheSeekableStream extends AbstractCachedSeekableStream
checkOpen(); checkOpen();
int length; int length;
if (mPosition == mStreamPosition) { if (position == streamPosition) {
// Read bytes from the stream // Read bytes from the stream
length = readAhead(pBytes, pOffset, pLength); length = readAhead(pBytes, pOffset, pLength);
@@ -198,83 +169,29 @@ public final class FileCacheSeekableStream extends AbstractCachedSeekableStream
else { else {
// ...or read bytes from the cache // ...or read bytes from the cache
syncPosition(); syncPosition();
length = getCache().read(pBytes, pOffset, (int) Math.min(pLength, mStreamPosition - mPosition)); length = getCache().read(pBytes, pOffset, (int) Math.min(pLength, streamPosition - position));
//System.out.println("Read " + length + " byte from cache"); //System.out.println("Read " + length + " byte from cache");
} }
// TODO: This field is not REALLY considered accessible.. :-P // TODO: This field is not REALLY considered accessible.. :-P
if (length > 0) { if (length > 0) {
mPosition += length; position += length;
} }
return length; return length;
} }
private int readAhead(final byte[] pBytes, final int pOffset, final int pLength) throws IOException { private int readAhead(final byte[] pBytes, final int pOffset, final int pLength) throws IOException {
int length; int length;
length = mStream.read(pBytes, pOffset, pLength); length = stream.read(pBytes, pOffset, pLength);
if (length > 0) { if (length > 0) {
mStreamPosition += length; streamPosition += length;
getCache().write(pBytes, pOffset, length); getCache().write(pBytes, pOffset, length);
} }
return length; return length;
} }
/*
private void syncPosition() throws IOException {
if (mCache.getFilePointer() != mPosition) {
mCache.seek(mPosition); // Assure EOF is correctly thrown
}
}
// Seekable overrides
protected void flushBeforeImpl(long pPosition) {
// TODO: Implement
// For now, it's probably okay to do nothing, this is just for
// performance (as long as people follow spec, not behaviour)
}
protected void seekImpl(long pPosition) throws IOException {
if (mStreamPosition < pPosition) {
// Make sure we append at end of cache
if (mCache.getFilePointer() != mStreamPosition) {
mCache.seek(mStreamPosition);
}
// Read diff from stream into cache
long left = pPosition - mStreamPosition;
int bufferLen = left > 1024 ? 1024 : (int) left;
byte[] buffer = new byte[bufferLen];
while (left > 0) {
int length = buffer.length < left ? buffer.length : (int) left;
int read = mStream.read(buffer, 0, length);
if (read > 0) {
mCache.write(buffer, 0, read);
mStreamPosition += read;
left -= read;
}
else if (read < 0) {
break;
}
}
}
else if (mStreamPosition >= pPosition) {
// Seek backwards into the cache
mCache.seek(pPosition);
}
// System.out.println("pPosition: " + pPosition);
// System.out.println("mStreamPosition: " + mStreamPosition);
// System.out.println("mCache.getFilePointer(): " + mCache.getFilePointer());
// NOTE: If mPosition == pPosition then we're good to go
}
*/
final static class FileCache extends StreamCache { final static class FileCache extends StreamCache {
private RandomAccessFile mCacheFile; private RandomAccessFile mCacheFile;

View File

@@ -87,7 +87,7 @@ public final class FileSeekableStream extends SeekableInputStream {
@Override @Override
public int available() throws IOException { public int available() throws IOException {
long length = mRandomAccess.length() - mPosition; long length = mRandomAccess.length() - position;
return length > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) length; return length > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) length;
} }
@@ -100,7 +100,7 @@ public final class FileSeekableStream extends SeekableInputStream {
int read = mRandomAccess.read(); int read = mRandomAccess.read();
if (read >= 0) { if (read >= 0) {
mPosition++; position++;
} }
return read; return read;
} }
@@ -111,7 +111,7 @@ public final class FileSeekableStream extends SeekableInputStream {
int read = mRandomAccess.read(pBytes, pOffset, pLength); int read = mRandomAccess.read(pBytes, pOffset, pLength);
if (read > 0) { if (read > 0) {
mPosition += read; position += read;
} }
return read; return read;
} }

View File

@@ -80,10 +80,10 @@ abstract class FileSystem {
} }
private static class UnknownFileSystem extends FileSystem { private static class UnknownFileSystem extends FileSystem {
private final String mOSName; private final String osName;
UnknownFileSystem(String pOSName) { UnknownFileSystem(String pOSName) {
mOSName = pOSName; osName = pOSName;
} }
long getFreeSpace(File pPath) { long getFreeSpace(File pPath) {
@@ -95,7 +95,7 @@ abstract class FileSystem {
} }
String getName() { String getName() {
return "Unknown (" + mOSName + ")"; return "Unknown (" + osName + ")";
} }
} }
} }

View File

@@ -685,28 +685,28 @@ public final class FileUtil {
// a file array, which may throw OutOfMemoryExceptions for // a file array, which may throw OutOfMemoryExceptions for
// large directories/in low memory situations // large directories/in low memory situations
class DeleteFilesVisitor implements Visitor<File> { class DeleteFilesVisitor implements Visitor<File> {
private int mFailedCount = 0; private int failedCount = 0;
private IOException mException = null; private IOException exception = null;
public void visit(final File pFile) { public void visit(final File pFile) {
try { try {
if (!delete(pFile, true)) { if (!delete(pFile, true)) {
mFailedCount++; failedCount++;
} }
} }
catch (IOException e) { catch (IOException e) {
mFailedCount++; failedCount++;
if (mException == null) { if (exception == null) {
mException = e; exception = e;
} }
} }
} }
boolean succeeded() throws IOException { boolean succeeded() throws IOException {
if (mException != null) { if (exception != null) {
throw mException; throw exception;
} }
return mFailedCount == 0; return failedCount == 0;
} }
} }
DeleteFilesVisitor fileDeleter = new DeleteFilesVisitor(); DeleteFilesVisitor fileDeleter = new DeleteFilesVisitor();

View File

@@ -60,9 +60,9 @@ import java.io.FilenameFilter;
public class FilenameMaskFilter implements FilenameFilter { public class FilenameMaskFilter implements FilenameFilter {
// Members // Members
private String[] mFilenameMasksForInclusion; private String[] filenameMasksForInclusion;
private String[] mFilenameMasksForExclusion; private String[] filenameMasksForExclusion;
private boolean mInclusion = true; private boolean inclusion = true;
/** /**
@@ -127,29 +127,29 @@ public class FilenameMaskFilter implements FilenameFilter {
* @param pFilenameMasksForInclusion the filename masks to include * @param pFilenameMasksForInclusion the filename masks to include
*/ */
public void setFilenameMasksForInclusion(String[] pFilenameMasksForInclusion) { public void setFilenameMasksForInclusion(String[] pFilenameMasksForInclusion) {
mFilenameMasksForInclusion = pFilenameMasksForInclusion; filenameMasksForInclusion = pFilenameMasksForInclusion;
} }
/** /**
* @return the current inclusion masks * @return the current inclusion masks
*/ */
public String[] getFilenameMasksForInclusion() { public String[] getFilenameMasksForInclusion() {
return mFilenameMasksForInclusion.clone(); return filenameMasksForInclusion.clone();
} }
/** /**
* @param pFilenameMasksForExclusion the filename masks to exclude * @param pFilenameMasksForExclusion the filename masks to exclude
*/ */
public void setFilenameMasksForExclusion(String[] pFilenameMasksForExclusion) { public void setFilenameMasksForExclusion(String[] pFilenameMasksForExclusion) {
mFilenameMasksForExclusion = pFilenameMasksForExclusion; filenameMasksForExclusion = pFilenameMasksForExclusion;
mInclusion = false; inclusion = false;
} }
/** /**
* @return the current exclusion masks * @return the current exclusion masks
*/ */
public String[] getFilenameMasksForExclusion() { public String[] getFilenameMasksForExclusion() {
return mFilenameMasksForExclusion.clone(); return filenameMasksForExclusion.clone();
} }
/** /**
@@ -164,8 +164,8 @@ public class FilenameMaskFilter implements FilenameFilter {
WildcardStringParser parser; WildcardStringParser parser;
// Check each filename string mask whether the file is to be accepted // Check each filename string mask whether the file is to be accepted
if (mInclusion) { // Inclusion if (inclusion) { // Inclusion
for (String mask : mFilenameMasksForInclusion) { for (String mask : filenameMasksForInclusion) {
parser = new WildcardStringParser(mask); parser = new WildcardStringParser(mask);
if (parser.parseString(pName)) { if (parser.parseString(pName)) {
@@ -181,7 +181,7 @@ public class FilenameMaskFilter implements FilenameFilter {
} }
else { else {
// Exclusion // Exclusion
for (String mask : mFilenameMasksForExclusion) { for (String mask : filenameMasksForExclusion) {
parser = new WildcardStringParser(mask); parser = new WildcardStringParser(mask);
if (parser.parseString(pName)) { if (parser.parseString(pName)) {
@@ -204,32 +204,32 @@ public class FilenameMaskFilter implements FilenameFilter {
StringBuilder retVal = new StringBuilder(); StringBuilder retVal = new StringBuilder();
int i; int i;
if (mInclusion) { if (inclusion) {
// Inclusion // Inclusion
if (mFilenameMasksForInclusion == null) { if (filenameMasksForInclusion == null) {
retVal.append("No filename masks set - property mFilenameMasksForInclusion is null!"); retVal.append("No filename masks set - property filenameMasksForInclusion is null!");
} }
else { else {
retVal.append(mFilenameMasksForInclusion.length); retVal.append(filenameMasksForInclusion.length);
retVal.append(" filename mask(s) - "); retVal.append(" filename mask(s) - ");
for (i = 0; i < mFilenameMasksForInclusion.length; i++) { for (i = 0; i < filenameMasksForInclusion.length; i++) {
retVal.append("\""); retVal.append("\"");
retVal.append(mFilenameMasksForInclusion[i]); retVal.append(filenameMasksForInclusion[i]);
retVal.append("\", \""); retVal.append("\", \"");
} }
} }
} }
else { else {
// Exclusion // Exclusion
if (mFilenameMasksForExclusion == null) { if (filenameMasksForExclusion == null) {
retVal.append("No filename masks set - property mFilenameMasksForExclusion is null!"); retVal.append("No filename masks set - property filenameMasksForExclusion is null!");
} }
else { else {
retVal.append(mFilenameMasksForExclusion.length); retVal.append(filenameMasksForExclusion.length);
retVal.append(" exclusion filename mask(s) - "); retVal.append(" exclusion filename mask(s) - ");
for (i = 0; i < mFilenameMasksForExclusion.length; i++) { for (i = 0; i < filenameMasksForExclusion.length; i++) {
retVal.append("\""); retVal.append("\"");
retVal.append(mFilenameMasksForExclusion[i]); retVal.append(filenameMasksForExclusion[i]);
retVal.append("\", \""); retVal.append("\", \"");
} }
} }

View File

@@ -1,93 +0,0 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.io;
import com.twelvemonkeys.lang.StringUtil;
import java.io.File;
import java.io.FilenameFilter;
/**
* A Java Bean used for approving file names which are to be included in a
* {@code java.io.File} listing. The file name suffixes are used as a
* filter input and is given to the class via the string array property:<br>
* <dd>{@code filenameSuffixesToExclude}
* <p>
* A recommended way of doing this is by referencing to the component which uses
* this class for file listing. In this way all properties are set in the same
* component and this utility component is kept in the background with only
* initial configuration necessary.
*
* @author <a href="mailto:eirik.torske@iconmedialab.no">Eirik Torske</a>
* @see File#list(java.io.FilenameFilter) java.io.File.list
* @see FilenameFilter java.io.FilenameFilter
*/
public class FilenameSuffixFilter implements FilenameFilter {
// Members
String[] mFilenameSuffixesToExclude;
/** Creates a {@code FileNameSuffixFilter} */
public FilenameSuffixFilter() {
}
public void setFilenameSuffixesToExclude(String[] pFilenameSuffixesToExclude) {
mFilenameSuffixesToExclude = pFilenameSuffixesToExclude;
}
public String[] getFilenameSuffixesToExclude() {
return mFilenameSuffixesToExclude;
}
/**
* This method implements the {@code java.io.FilenameFilter} interface.
* <p/>
*
* @param pDir the directory in which the file was found.
* @param pName the pName of the file.
* @return {@code true} if the pName should be included in the file list;
* {@code false} otherwise.
*/
public boolean accept(final File pDir, final String pName) {
if (StringUtil.isEmpty(mFilenameSuffixesToExclude)) {
return true;
}
for (String aMFilenameSuffixesToExclude : mFilenameSuffixesToExclude) {
// -- Edit by haraldK, to make interfaces more consistent
// if (StringUtil.filenameSuffixIs(pName, mFilenameSuffixesToExclude[i])) {
if (aMFilenameSuffixesToExclude.equals(FileUtil.getExtension(pName))) {
return false;
}
}
return true;
}
}

View File

@@ -38,6 +38,8 @@
package com.twelvemonkeys.io; package com.twelvemonkeys.io;
import com.twelvemonkeys.lang.Validate;
import java.io.*; import java.io.*;
/** /**
@@ -75,10 +77,7 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
* @see java.io.FilterInputStream#in * @see java.io.FilterInputStream#in
*/ */
public LittleEndianDataInputStream(final InputStream pStream) { public LittleEndianDataInputStream(final InputStream pStream) {
super(pStream); super(Validate.notNull(pStream, "stream"));
if (pStream == null) {
throw new IllegalArgumentException("stream == null");
}
} }
/** /**
@@ -93,9 +92,11 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
*/ */
public boolean readBoolean() throws IOException { public boolean readBoolean() throws IOException {
int b = in.read(); int b = in.read();
if (b < 0) { if (b < 0) {
throw new EOFException(); throw new EOFException();
} }
return b != 0; return b != 0;
} }
@@ -110,9 +111,11 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
*/ */
public byte readByte() throws IOException { public byte readByte() throws IOException {
int b = in.read(); int b = in.read();
if (b < 0) { if (b < 0) {
throw new EOFException(); throw new EOFException();
} }
return (byte) b; return (byte) b;
} }
@@ -128,9 +131,11 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
*/ */
public int readUnsignedByte() throws IOException { public int readUnsignedByte() throws IOException {
int b = in.read(); int b = in.read();
if (b < 0) { if (b < 0) {
throw new EOFException(); throw new EOFException();
} }
return b; return b;
} }
@@ -146,11 +151,13 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
public short readShort() throws IOException { public short readShort() throws IOException {
int byte1 = in.read(); int byte1 = in.read();
int byte2 = in.read(); int byte2 = in.read();
// only need to test last byte read // only need to test last byte read
// if byte1 is -1 so is byte2 // if byte1 is -1 so is byte2
if (byte2 < 0) { if (byte2 < 0) {
throw new EOFException(); throw new EOFException();
} }
return (short) (((byte2 << 24) >>> 16) + (byte1 << 24) >>> 24); return (short) (((byte2 << 24) >>> 16) + (byte1 << 24) >>> 24);
} }
@@ -166,10 +173,11 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
public int readUnsignedShort() throws IOException { public int readUnsignedShort() throws IOException {
int byte1 = in.read(); int byte1 = in.read();
int byte2 = in.read(); int byte2 = in.read();
if (byte2 < 0) { if (byte2 < 0) {
throw new EOFException(); throw new EOFException();
} }
//return ((byte2 << 24) >> 16) + ((byte1 << 24) >> 24);
return (byte2 << 8) + byte1; return (byte2 << 8) + byte1;
} }
@@ -185,9 +193,11 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
public char readChar() throws IOException { public char readChar() throws IOException {
int byte1 = in.read(); int byte1 = in.read();
int byte2 = in.read(); int byte2 = in.read();
if (byte2 < 0) { if (byte2 < 0) {
throw new EOFException(); throw new EOFException();
} }
return (char) (((byte2 << 24) >>> 16) + ((byte1 << 24) >>> 24)); return (char) (((byte2 << 24) >>> 16) + ((byte1 << 24) >>> 24));
} }
@@ -210,6 +220,7 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
if (byte4 < 0) { if (byte4 < 0) {
throw new EOFException(); throw new EOFException();
} }
return (byte4 << 24) + ((byte3 << 24) >>> 8) return (byte4 << 24) + ((byte3 << 24) >>> 8)
+ ((byte2 << 24) >>> 16) + ((byte1 << 24) >>> 24); + ((byte2 << 24) >>> 16) + ((byte1 << 24) >>> 24);
} }
@@ -236,11 +247,11 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
if (byte8 < 0) { if (byte8 < 0) {
throw new EOFException(); throw new EOFException();
} }
return (byte8 << 56) + ((byte7 << 56) >>> 8) return (byte8 << 56) + ((byte7 << 56) >>> 8)
+ ((byte6 << 56) >>> 16) + ((byte5 << 56) >>> 24) + ((byte6 << 56) >>> 16) + ((byte5 << 56) >>> 24)
+ ((byte4 << 56) >>> 32) + ((byte3 << 56) >>> 40) + ((byte4 << 56) >>> 32) + ((byte3 << 56) >>> 40)
+ ((byte2 << 56) >>> 48) + ((byte1 << 56) >>> 56); + ((byte2 << 56) >>> 48) + ((byte1 << 56) >>> 56);
} }
/** /**
@@ -260,16 +271,17 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
public String readUTF() throws IOException { public String readUTF() throws IOException {
int byte1 = in.read(); int byte1 = in.read();
int byte2 = in.read(); int byte2 = in.read();
if (byte2 < 0) { if (byte2 < 0) {
throw new EOFException(); throw new EOFException();
} }
int numbytes = (byte1 << 8) + byte2; int numbytes = (byte1 << 8) + byte2;
char result[] = new char[numbytes]; char result[] = new char[numbytes];
int numread = 0; int numread = 0;
int numchars = 0; int numchars = 0;
while (numread < numbytes) { while (numread < numbytes) {
int c1 = readUnsignedByte(); int c1 = readUnsignedByte();
int c2, c3; int c2, c3;
@@ -281,27 +293,34 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
} }
else if (test == 12 || test == 13) { // two bytes else if (test == 12 || test == 13) { // two bytes
numread += 2; numread += 2;
if (numread > numbytes) { if (numread > numbytes) {
throw new UTFDataFormatException(); throw new UTFDataFormatException();
} }
c2 = readUnsignedByte(); c2 = readUnsignedByte();
if ((c2 & 0xC0) != 0x80) { if ((c2 & 0xC0) != 0x80) {
throw new UTFDataFormatException(); throw new UTFDataFormatException();
} }
result[numchars++] = (char) (((c1 & 0x1F) << 6) | (c2 & 0x3F)); result[numchars++] = (char) (((c1 & 0x1F) << 6) | (c2 & 0x3F));
} }
else if (test == 14) { // three bytes else if (test == 14) { // three bytes
numread += 3; numread += 3;
if (numread > numbytes) { if (numread > numbytes) {
throw new UTFDataFormatException(); throw new UTFDataFormatException();
} }
c2 = readUnsignedByte(); c2 = readUnsignedByte();
c3 = readUnsignedByte(); c3 = readUnsignedByte();
if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) { if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) {
throw new UTFDataFormatException(); throw new UTFDataFormatException();
} }
result[numchars++] = (char)
(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F)); result[numchars++] = (char) (((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
} }
else { // malformed else { // malformed
throw new UTFDataFormatException(); throw new UTFDataFormatException();
@@ -396,12 +415,16 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
if (pLength < 0) { if (pLength < 0) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
int count = 0; int count = 0;
while (count < pLength) { while (count < pLength) {
int read = in.read(pBytes, pOffset + count, pLength - count); int read = in.read(pBytes, pOffset + count, pLength - count);
if (read < 0) { if (read < 0) {
throw new EOFException(); throw new EOFException();
} }
count += read; count += read;
} }
} }

View File

@@ -38,6 +38,8 @@
package com.twelvemonkeys.io; package com.twelvemonkeys.io;
import com.twelvemonkeys.lang.Validate;
import java.io.*; import java.io.*;
/** /**
@@ -69,7 +71,7 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
/** /**
* The number of bytes written so far to the little endian output stream. * The number of bytes written so far to the little endian output stream.
*/ */
protected int mWritten; protected int bytesWritten;
/** /**
* Creates a new little endian output stream and chains it to the * Creates a new little endian output stream and chains it to the
@@ -79,10 +81,7 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
* @see java.io.FilterOutputStream#out * @see java.io.FilterOutputStream#out
*/ */
public LittleEndianDataOutputStream(OutputStream pStream) { public LittleEndianDataOutputStream(OutputStream pStream) {
super(pStream); super(Validate.notNull(pStream, "stream"));
if (pStream == null) {
throw new IllegalArgumentException("stream == null");
}
} }
/** /**
@@ -93,7 +92,7 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
*/ */
public synchronized void write(int pByte) throws IOException { public synchronized void write(int pByte) throws IOException {
out.write(pByte); out.write(pByte);
mWritten++; bytesWritten++;
} }
/** /**
@@ -105,10 +104,9 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
* @param pLength the number of bytes to write. * @param pLength the number of bytes to write.
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public synchronized void write(byte[] pBytes, int pOffset, int pLength) public synchronized void write(byte[] pBytes, int pOffset, int pLength) throws IOException {
throws IOException {
out.write(pBytes, pOffset, pLength); out.write(pBytes, pOffset, pLength);
mWritten += pLength; bytesWritten += pLength;
} }
@@ -137,7 +135,7 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
*/ */
public void writeByte(int pByte) throws IOException { public void writeByte(int pByte) throws IOException {
out.write(pByte); out.write(pByte);
mWritten++; bytesWritten++;
} }
/** /**
@@ -150,7 +148,7 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
public void writeShort(int pShort) throws IOException { public void writeShort(int pShort) throws IOException {
out.write(pShort & 0xFF); out.write(pShort & 0xFF);
out.write((pShort >>> 8) & 0xFF); out.write((pShort >>> 8) & 0xFF);
mWritten += 2; bytesWritten += 2;
} }
/** /**
@@ -163,7 +161,7 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
public void writeChar(int pChar) throws IOException { public void writeChar(int pChar) throws IOException {
out.write(pChar & 0xFF); out.write(pChar & 0xFF);
out.write((pChar >>> 8) & 0xFF); out.write((pChar >>> 8) & 0xFF);
mWritten += 2; bytesWritten += 2;
} }
/** /**
@@ -178,7 +176,7 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
out.write((pInt >>> 8) & 0xFF); out.write((pInt >>> 8) & 0xFF);
out.write((pInt >>> 16) & 0xFF); out.write((pInt >>> 16) & 0xFF);
out.write((pInt >>> 24) & 0xFF); out.write((pInt >>> 24) & 0xFF);
mWritten += 4; bytesWritten += 4;
} }
@@ -198,7 +196,7 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
out.write((int) (pLong >>> 40) & 0xFF); out.write((int) (pLong >>> 40) & 0xFF);
out.write((int) (pLong >>> 48) & 0xFF); out.write((int) (pLong >>> 48) & 0xFF);
out.write((int) (pLong >>> 56) & 0xFF); out.write((int) (pLong >>> 56) & 0xFF);
mWritten += 8; bytesWritten += 8;
} }
/** /**
@@ -235,10 +233,12 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
*/ */
public void writeBytes(String pString) throws IOException { public void writeBytes(String pString) throws IOException {
int length = pString.length(); int length = pString.length();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
out.write((byte) pString.charAt(i)); out.write((byte) pString.charAt(i));
} }
mWritten += length;
bytesWritten += length;
} }
/** /**
@@ -253,12 +253,14 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
*/ */
public void writeChars(String pString) throws IOException { public void writeChars(String pString) throws IOException {
int length = pString.length(); int length = pString.length();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
int c = pString.charAt(i); int c = pString.charAt(i);
out.write(c & 0xFF); out.write(c & 0xFF);
out.write((c >>> 8) & 0xFF); out.write((c >>> 8) & 0xFF);
} }
mWritten += length * 2;
bytesWritten += length * 2;
} }
/** /**
@@ -282,6 +284,7 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
for (int i = 0; i < numchars; i++) { for (int i = 0; i < numchars; i++) {
int c = pString.charAt(i); int c = pString.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) { if ((c >= 0x0001) && (c <= 0x007F)) {
numbytes++; numbytes++;
} }
@@ -299,8 +302,10 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
out.write((numbytes >>> 8) & 0xFF); out.write((numbytes >>> 8) & 0xFF);
out.write(numbytes & 0xFF); out.write(numbytes & 0xFF);
for (int i = 0; i < numchars; i++) { for (int i = 0; i < numchars; i++) {
int c = pString.charAt(i); int c = pString.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) { if ((c >= 0x0001) && (c <= 0x007F)) {
out.write(c); out.write(c);
} }
@@ -308,16 +313,16 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
out.write(0xE0 | ((c >> 12) & 0x0F)); out.write(0xE0 | ((c >> 12) & 0x0F));
out.write(0x80 | ((c >> 6) & 0x3F)); out.write(0x80 | ((c >> 6) & 0x3F));
out.write(0x80 | (c & 0x3F)); out.write(0x80 | (c & 0x3F));
mWritten += 2; bytesWritten += 2;
} }
else { else {
out.write(0xC0 | ((c >> 6) & 0x1F)); out.write(0xC0 | ((c >> 6) & 0x1F));
out.write(0x80 | (c & 0x3F)); out.write(0x80 | (c & 0x3F));
mWritten += 1; bytesWritten += 1;
} }
} }
mWritten += numchars + 2; bytesWritten += numchars + 2;
} }
/** /**
@@ -326,9 +331,9 @@ public class LittleEndianDataOutputStream extends FilterOutputStream implements
* possible that this number is temporarily less than the actual * possible that this number is temporarily less than the actual
* number of bytes written.) * number of bytes written.)
* @return the value of the {@code written} field. * @return the value of the {@code written} field.
* @see #mWritten * @see #bytesWritten
*/ */
public int size() { public int size() {
return mWritten; return bytesWritten;
} }
} }

View File

@@ -56,58 +56,58 @@ import java.nio.channels.FileChannel;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/LittleEndianRandomAccessFile.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/LittleEndianRandomAccessFile.java#1 $
*/ */
public class LittleEndianRandomAccessFile implements DataInput, DataOutput { public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
private RandomAccessFile mFile; private RandomAccessFile file;
public LittleEndianRandomAccessFile(final String pName, final String pMode) throws FileNotFoundException { public LittleEndianRandomAccessFile(final String pName, final String pMode) throws FileNotFoundException {
this(FileUtil.resolve(pName), pMode); this(FileUtil.resolve(pName), pMode);
} }
public LittleEndianRandomAccessFile(final File pFile, final String pMode) throws FileNotFoundException { public LittleEndianRandomAccessFile(final File pFile, final String pMode) throws FileNotFoundException {
mFile = new RandomAccessFile(pFile, pMode); file = new RandomAccessFile(pFile, pMode);
} }
public void close() throws IOException { public void close() throws IOException {
mFile.close(); file.close();
} }
public FileChannel getChannel() { public FileChannel getChannel() {
return mFile.getChannel(); return file.getChannel();
} }
public FileDescriptor getFD() throws IOException { public FileDescriptor getFD() throws IOException {
return mFile.getFD(); return file.getFD();
} }
public long getFilePointer() throws IOException { public long getFilePointer() throws IOException {
return mFile.getFilePointer(); return file.getFilePointer();
} }
public long length() throws IOException { public long length() throws IOException {
return mFile.length(); return file.length();
} }
public int read() throws IOException { public int read() throws IOException {
return mFile.read(); return file.read();
} }
public int read(final byte[] b) throws IOException { public int read(final byte[] b) throws IOException {
return mFile.read(b); return file.read(b);
} }
public int read(final byte[] b, final int off, final int len) throws IOException { public int read(final byte[] b, final int off, final int len) throws IOException {
return mFile.read(b, off, len); return file.read(b, off, len);
} }
public void readFully(final byte[] b) throws IOException { public void readFully(final byte[] b) throws IOException {
mFile.readFully(b); file.readFully(b);
} }
public void readFully(final byte[] b, final int off, final int len) throws IOException { public void readFully(final byte[] b, final int off, final int len) throws IOException {
mFile.readFully(b, off, len); file.readFully(b, off, len);
} }
public String readLine() throws IOException { public String readLine() throws IOException {
return mFile.readLine(); return file.readLine();
} }
/** /**
@@ -121,10 +121,12 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public boolean readBoolean() throws IOException { public boolean readBoolean() throws IOException {
int b = mFile.read(); int b = file.read();
if (b < 0) { if (b < 0) {
throw new EOFException(); throw new EOFException();
} }
return b != 0; return b != 0;
} }
@@ -138,10 +140,12 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public byte readByte() throws IOException { public byte readByte() throws IOException {
int b = mFile.read(); int b = file.read();
if (b < 0) { if (b < 0) {
throw new EOFException(); throw new EOFException();
} }
return (byte) b; return (byte) b;
} }
@@ -156,10 +160,12 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public int readUnsignedByte() throws IOException { public int readUnsignedByte() throws IOException {
int b = mFile.read(); int b = file.read();
if (b < 0) { if (b < 0) {
throw new EOFException(); throw new EOFException();
} }
return b; return b;
} }
@@ -173,13 +179,15 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public short readShort() throws IOException { public short readShort() throws IOException {
int byte1 = mFile.read(); int byte1 = file.read();
int byte2 = mFile.read(); int byte2 = file.read();
// only need to test last byte read // only need to test last byte read
// if byte1 is -1 so is byte2 // if byte1 is -1 so is byte2
if (byte2 < 0) { if (byte2 < 0) {
throw new EOFException(); throw new EOFException();
} }
return (short) (((byte2 << 24) >>> 16) + (byte1 << 24) >>> 24); return (short) (((byte2 << 24) >>> 16) + (byte1 << 24) >>> 24);
} }
@@ -193,11 +201,13 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public int readUnsignedShort() throws IOException { public int readUnsignedShort() throws IOException {
int byte1 = mFile.read(); int byte1 = file.read();
int byte2 = mFile.read(); int byte2 = file.read();
if (byte2 < 0) { if (byte2 < 0) {
throw new EOFException(); throw new EOFException();
} }
//return ((byte2 << 24) >> 16) + ((byte1 << 24) >> 24); //return ((byte2 << 24) >> 16) + ((byte1 << 24) >> 24);
return (byte2 << 8) + byte1; return (byte2 << 8) + byte1;
} }
@@ -212,11 +222,13 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public char readChar() throws IOException { public char readChar() throws IOException {
int byte1 = mFile.read(); int byte1 = file.read();
int byte2 = mFile.read(); int byte2 = file.read();
if (byte2 < 0) { if (byte2 < 0) {
throw new EOFException(); throw new EOFException();
} }
return (char) (((byte2 << 24) >>> 16) + ((byte1 << 24) >>> 24)); return (char) (((byte2 << 24) >>> 16) + ((byte1 << 24) >>> 24));
} }
@@ -231,16 +243,16 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public int readInt() throws IOException { public int readInt() throws IOException {
int byte1 = mFile.read(); int byte1 = file.read();
int byte2 = mFile.read(); int byte2 = file.read();
int byte3 = mFile.read(); int byte3 = file.read();
int byte4 = mFile.read(); int byte4 = file.read();
if (byte4 < 0) { if (byte4 < 0) {
throw new EOFException(); throw new EOFException();
} }
return (byte4 << 24) + ((byte3 << 24) >>> 8)
+ ((byte2 << 24) >>> 16) + ((byte1 << 24) >>> 24); return (byte4 << 24) + ((byte3 << 24) >>> 8) + ((byte2 << 24) >>> 16) + ((byte1 << 24) >>> 24);
} }
/** /**
@@ -253,18 +265,19 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public long readLong() throws IOException { public long readLong() throws IOException {
long byte1 = mFile.read(); long byte1 = file.read();
long byte2 = mFile.read(); long byte2 = file.read();
long byte3 = mFile.read(); long byte3 = file.read();
long byte4 = mFile.read(); long byte4 = file.read();
long byte5 = mFile.read(); long byte5 = file.read();
long byte6 = mFile.read(); long byte6 = file.read();
long byte7 = mFile.read(); long byte7 = file.read();
long byte8 = mFile.read(); long byte8 = file.read();
if (byte8 < 0) { if (byte8 < 0) {
throw new EOFException(); throw new EOFException();
} }
return (byte8 << 56) + ((byte7 << 56) >>> 8) return (byte8 << 56) + ((byte7 << 56) >>> 8)
+ ((byte6 << 56) >>> 16) + ((byte5 << 56) >>> 24) + ((byte6 << 56) >>> 16) + ((byte5 << 56) >>> 24)
+ ((byte4 << 56) >>> 32) + ((byte3 << 56) >>> 40) + ((byte4 << 56) >>> 32) + ((byte3 << 56) >>> 40)
@@ -287,11 +300,13 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public String readUTF() throws IOException { public String readUTF() throws IOException {
int byte1 = mFile.read(); int byte1 = file.read();
int byte2 = mFile.read(); int byte2 = file.read();
if (byte2 < 0) { if (byte2 < 0) {
throw new EOFException(); throw new EOFException();
} }
int numbytes = (byte1 << 8) + byte2; int numbytes = (byte1 << 8) + byte2;
char result[] = new char[numbytes]; char result[] = new char[numbytes];
int numread = 0; int numread = 0;
@@ -310,27 +325,34 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
} }
else if (test == 12 || test == 13) { // two bytes else if (test == 12 || test == 13) { // two bytes
numread += 2; numread += 2;
if (numread > numbytes) { if (numread > numbytes) {
throw new UTFDataFormatException(); throw new UTFDataFormatException();
} }
c2 = readUnsignedByte(); c2 = readUnsignedByte();
if ((c2 & 0xC0) != 0x80) { if ((c2 & 0xC0) != 0x80) {
throw new UTFDataFormatException(); throw new UTFDataFormatException();
} }
result[numchars++] = (char) (((c1 & 0x1F) << 6) | (c2 & 0x3F)); result[numchars++] = (char) (((c1 & 0x1F) << 6) | (c2 & 0x3F));
} }
else if (test == 14) { // three bytes else if (test == 14) { // three bytes
numread += 3; numread += 3;
if (numread > numbytes) { if (numread > numbytes) {
throw new UTFDataFormatException(); throw new UTFDataFormatException();
} }
c2 = readUnsignedByte(); c2 = readUnsignedByte();
c3 = readUnsignedByte(); c3 = readUnsignedByte();
if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) { if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) {
throw new UTFDataFormatException(); throw new UTFDataFormatException();
} }
result[numchars++] = (char)
(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F)); result[numchars++] = (char) (((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
} }
else { // malformed else { // malformed
throw new UTFDataFormatException(); throw new UTFDataFormatException();
@@ -378,27 +400,27 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* {@code 0} or if an I/O error occurs. * {@code 0} or if an I/O error occurs.
*/ */
public void seek(final long pos) throws IOException { public void seek(final long pos) throws IOException {
mFile.seek(pos); file.seek(pos);
} }
public void setLength(final long newLength) throws IOException { public void setLength(final long newLength) throws IOException {
mFile.setLength(newLength); file.setLength(newLength);
} }
public int skipBytes(final int n) throws IOException { public int skipBytes(final int n) throws IOException {
return mFile.skipBytes(n); return file.skipBytes(n);
} }
public void write(final byte[] b) throws IOException { public void write(final byte[] b) throws IOException {
mFile.write(b); file.write(b);
} }
public void write(final byte[] b, final int off, final int len) throws IOException { public void write(final byte[] b, final int off, final int len) throws IOException {
mFile.write(b, off, len); file.write(b, off, len);
} }
public void write(final int b) throws IOException { public void write(final int b) throws IOException {
mFile.write(b); file.write(b);
} }
/** /**
@@ -425,7 +447,7 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public void writeByte(int pByte) throws IOException { public void writeByte(int pByte) throws IOException {
mFile.write(pByte); file.write(pByte);
} }
/** /**
@@ -436,8 +458,8 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public void writeShort(int pShort) throws IOException { public void writeShort(int pShort) throws IOException {
mFile.write(pShort & 0xFF); file.write(pShort & 0xFF);
mFile.write((pShort >>> 8) & 0xFF); file.write((pShort >>> 8) & 0xFF);
} }
/** /**
@@ -448,8 +470,8 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public void writeChar(int pChar) throws IOException { public void writeChar(int pChar) throws IOException {
mFile.write(pChar & 0xFF); file.write(pChar & 0xFF);
mFile.write((pChar >>> 8) & 0xFF); file.write((pChar >>> 8) & 0xFF);
} }
/** /**
@@ -460,11 +482,10 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public void writeInt(int pInt) throws IOException { public void writeInt(int pInt) throws IOException {
mFile.write(pInt & 0xFF); file.write(pInt & 0xFF);
mFile.write((pInt >>> 8) & 0xFF); file.write((pInt >>> 8) & 0xFF);
mFile.write((pInt >>> 16) & 0xFF); file.write((pInt >>> 16) & 0xFF);
mFile.write((pInt >>> 24) & 0xFF); file.write((pInt >>> 24) & 0xFF);
} }
/** /**
@@ -475,14 +496,14 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
*/ */
public void writeLong(long pLong) throws IOException { public void writeLong(long pLong) throws IOException {
mFile.write((int) pLong & 0xFF); file.write((int) pLong & 0xFF);
mFile.write((int) (pLong >>> 8) & 0xFF); file.write((int) (pLong >>> 8) & 0xFF);
mFile.write((int) (pLong >>> 16) & 0xFF); file.write((int) (pLong >>> 16) & 0xFF);
mFile.write((int) (pLong >>> 24) & 0xFF); file.write((int) (pLong >>> 24) & 0xFF);
mFile.write((int) (pLong >>> 32) & 0xFF); file.write((int) (pLong >>> 32) & 0xFF);
mFile.write((int) (pLong >>> 40) & 0xFF); file.write((int) (pLong >>> 40) & 0xFF);
mFile.write((int) (pLong >>> 48) & 0xFF); file.write((int) (pLong >>> 48) & 0xFF);
mFile.write((int) (pLong >>> 56) & 0xFF); file.write((int) (pLong >>> 56) & 0xFF);
} }
/** /**
@@ -515,12 +536,13 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @param pString the {@code String} value to be written. * @param pString the {@code String} value to be written.
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
* @see #writeByte(int) * @see #writeByte(int)
* @see #mFile * @see #file
*/ */
public void writeBytes(String pString) throws IOException { public void writeBytes(String pString) throws IOException {
int length = pString.length(); int length = pString.length();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
mFile.write((byte) pString.charAt(i)); file.write((byte) pString.charAt(i));
} }
} }
@@ -532,14 +554,15 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
* @param pString a {@code String} value to be written. * @param pString a {@code String} value to be written.
* @throws IOException if the underlying stream throws an IOException. * @throws IOException if the underlying stream throws an IOException.
* @see #writeChar(int) * @see #writeChar(int)
* @see #mFile * @see #file
*/ */
public void writeChars(String pString) throws IOException { public void writeChars(String pString) throws IOException {
int length = pString.length(); int length = pString.length();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
int c = pString.charAt(i); int c = pString.charAt(i);
mFile.write(c & 0xFF); file.write(c & 0xFF);
mFile.write((c >>> 8) & 0xFF); file.write((c >>> 8) & 0xFF);
} }
} }
@@ -564,6 +587,7 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
for (int i = 0; i < numchars; i++) { for (int i = 0; i < numchars; i++) {
int c = pString.charAt(i); int c = pString.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) { if ((c >= 0x0001) && (c <= 0x007F)) {
numbytes++; numbytes++;
} }
@@ -579,21 +603,23 @@ public class LittleEndianRandomAccessFile implements DataInput, DataOutput {
throw new UTFDataFormatException(); throw new UTFDataFormatException();
} }
mFile.write((numbytes >>> 8) & 0xFF); file.write((numbytes >>> 8) & 0xFF);
mFile.write(numbytes & 0xFF); file.write(numbytes & 0xFF);
for (int i = 0; i < numchars; i++) { for (int i = 0; i < numchars; i++) {
int c = pString.charAt(i); int c = pString.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) { if ((c >= 0x0001) && (c <= 0x007F)) {
mFile.write(c); file.write(c);
} }
else if (c > 0x07FF) { else if (c > 0x07FF) {
mFile.write(0xE0 | ((c >> 12) & 0x0F)); file.write(0xE0 | ((c >> 12) & 0x0F));
mFile.write(0x80 | ((c >> 6) & 0x3F)); file.write(0x80 | ((c >> 6) & 0x3F));
mFile.write(0x80 | (c & 0x3F)); file.write(0x80 | (c & 0x3F));
} }
else { else {
mFile.write(0xC0 | ((c >> 6) & 0x1F)); file.write(0xC0 | ((c >> 6) & 0x1F));
mFile.write(0x80 | (c & 0x3F)); file.write(0x80 | (c & 0x3F));
} }
} }
} }

View File

@@ -65,13 +65,13 @@ public final class MemoryCacheSeekableStream extends AbstractCachedSeekableStrea
final static class MemoryCache extends StreamCache { final static class MemoryCache extends StreamCache {
final static int BLOCK_SIZE = 1 << 13; final static int BLOCK_SIZE = 1 << 13;
private final List<byte[]> mCache = new ArrayList<byte[]>(); private final List<byte[]> cache = new ArrayList<byte[]>();
private long mLength; private long length;
private long mPosition; private long position;
private long mStart; private long start;
private byte[] getBlock() throws IOException { private byte[] getBlock() throws IOException {
final long currPos = mPosition - mStart; final long currPos = position - start;
if (currPos < 0) { if (currPos < 0) {
throw new IOException("StreamCache flushed before read position"); throw new IOException("StreamCache flushed before read position");
} }
@@ -82,31 +82,31 @@ public final class MemoryCacheSeekableStream extends AbstractCachedSeekableStrea
throw new IOException("Memory cache max size exceeded"); throw new IOException("Memory cache max size exceeded");
} }
if (index >= mCache.size()) { if (index >= cache.size()) {
try { try {
mCache.add(new byte[BLOCK_SIZE]); cache.add(new byte[BLOCK_SIZE]);
// System.out.println("Allocating new block, size: " + BLOCK_SIZE); // System.out.println("Allocating new block, size: " + BLOCK_SIZE);
// System.out.println("New total size: " + mCache.size() * BLOCK_SIZE + " (" + mCache.size() + " blocks)"); // System.out.println("New total size: " + cache.size() * BLOCK_SIZE + " (" + cache.size() + " blocks)");
} }
catch (OutOfMemoryError e) { catch (OutOfMemoryError e) {
throw new IOException("No more memory for cache: " + mCache.size() * BLOCK_SIZE); throw new IOException("No more memory for cache: " + cache.size() * BLOCK_SIZE);
} }
} }
//System.out.println("index: " + index); //System.out.println("index: " + index);
return mCache.get((int) index); return cache.get((int) index);
} }
public void write(final int pByte) throws IOException { public void write(final int pByte) throws IOException {
byte[] buffer = getBlock(); byte[] buffer = getBlock();
int idx = (int) (mPosition % BLOCK_SIZE); int idx = (int) (position % BLOCK_SIZE);
buffer[idx] = (byte) pByte; buffer[idx] = (byte) pByte;
mPosition++; position++;
if (mPosition > mLength) { if (position > length) {
mLength = mPosition; length = position;
} }
} }
@@ -115,28 +115,28 @@ public final class MemoryCacheSeekableStream extends AbstractCachedSeekableStrea
public void write(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException { public void write(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException {
byte[] buffer = getBlock(); byte[] buffer = getBlock();
for (int i = 0; i < pLength; i++) { for (int i = 0; i < pLength; i++) {
int index = (int) mPosition % BLOCK_SIZE; int index = (int) position % BLOCK_SIZE;
if (index == 0) { if (index == 0) {
buffer = getBlock(); buffer = getBlock();
} }
buffer[index] = pBuffer[pOffset + i]; buffer[index] = pBuffer[pOffset + i];
mPosition++; position++;
} }
if (mPosition > mLength) { if (position > length) {
mLength = mPosition; length = position;
} }
} }
public int read() throws IOException { public int read() throws IOException {
if (mPosition >= mLength) { if (position >= length) {
return -1; return -1;
} }
byte[] buffer = getBlock(); byte[] buffer = getBlock();
int idx = (int) (mPosition % BLOCK_SIZE); int idx = (int) (position % BLOCK_SIZE);
mPosition++; position++;
return buffer[idx] & 0xff; return buffer[idx] & 0xff;
} }
@@ -144,33 +144,33 @@ public final class MemoryCacheSeekableStream extends AbstractCachedSeekableStrea
// TODO: OptimizeMe!!! // TODO: OptimizeMe!!!
@Override @Override
public int read(final byte[] pBytes, final int pOffset, final int pLength) throws IOException { public int read(final byte[] pBytes, final int pOffset, final int pLength) throws IOException {
if (mPosition >= mLength) { if (position >= length) {
return -1; return -1;
} }
byte[] buffer = getBlock(); byte[] buffer = getBlock();
int bufferPos = (int) (mPosition % BLOCK_SIZE); int bufferPos = (int) (position % BLOCK_SIZE);
// Find maxIdx and simplify test in for-loop // Find maxIdx and simplify test in for-loop
int maxLen = (int) Math.min(Math.min(pLength, buffer.length - bufferPos), mLength - mPosition); int maxLen = (int) Math.min(Math.min(pLength, buffer.length - bufferPos), length - position);
int i; int i;
//for (i = 0; i < pLength && i < buffer.length - idx && i < mLength - mPosition; i++) { //for (i = 0; i < pLength && i < buffer.length - idx && i < length - position; i++) {
for (i = 0; i < maxLen; i++) { for (i = 0; i < maxLen; i++) {
pBytes[pOffset + i] = buffer[bufferPos + i]; pBytes[pOffset + i] = buffer[bufferPos + i];
} }
mPosition += i; position += i;
return i; return i;
} }
public void seek(final long pPosition) throws IOException { public void seek(final long pPosition) throws IOException {
if (pPosition < mStart) { if (pPosition < start) {
throw new IOException("Seek before flush position"); throw new IOException("Seek before flush position");
} }
mPosition = pPosition; position = pPosition;
} }
@Override @Override
@@ -178,14 +178,14 @@ public final class MemoryCacheSeekableStream extends AbstractCachedSeekableStrea
int firstPos = (int) (pPosition / BLOCK_SIZE) - 1; int firstPos = (int) (pPosition / BLOCK_SIZE) - 1;
for (int i = 0; i < firstPos; i++) { for (int i = 0; i < firstPos; i++) {
mCache.remove(0); cache.remove(0);
} }
mStart = pPosition; start = pPosition;
} }
public long getPosition() { public long getPosition() {
return mPosition; return position;
} }
} }
} }

View File

@@ -50,13 +50,12 @@ public abstract class RandomAccessStream implements Seekable, DataInput, DataOut
// TODO: Package private SeekableDelegate? // TODO: Package private SeekableDelegate?
// TODO: Both read and write must update stream position // TODO: Both read and write must update stream position
//private int mPosition = -1; //private int position = -1;
/** This random access stream, wrapped in an {@code InputStream} */ /** This random access stream, wrapped in an {@code InputStream} */
SeekableInputStream mInputView = null; SeekableInputStream inputView = null;
/** This random access stream, wrapped in an {@code OutputStream} */ /** This random access stream, wrapped in an {@code OutputStream} */
SeekableOutputStream mOutputView = null; SeekableOutputStream outputView = null;
// TODO: Create an Input and an Output interface matching InputStream and OutputStream? // TODO: Create an Input and an Output interface matching InputStream and OutputStream?
public int read() throws IOException { public int read() throws IOException {
@@ -119,10 +118,10 @@ public abstract class RandomAccessStream implements Seekable, DataInput, DataOut
* @return a {@code SeekableInputStream} reading from this stream * @return a {@code SeekableInputStream} reading from this stream
*/ */
public final SeekableInputStream asInputStream() { public final SeekableInputStream asInputStream() {
if (mInputView == null) { if (inputView == null) {
mInputView = new InputStreamView(this); inputView = new InputStreamView(this);
} }
return mInputView; return inputView;
} }
/** /**
@@ -134,15 +133,15 @@ public abstract class RandomAccessStream implements Seekable, DataInput, DataOut
* @return a {@code SeekableOutputStream} writing to this stream * @return a {@code SeekableOutputStream} writing to this stream
*/ */
public final SeekableOutputStream asOutputStream() { public final SeekableOutputStream asOutputStream() {
if (mOutputView == null) { if (outputView == null) {
mOutputView = new OutputStreamView(this); outputView = new OutputStreamView(this);
} }
return mOutputView; return outputView;
} }
static final class InputStreamView extends SeekableInputStream { static final class InputStreamView extends SeekableInputStream {
// TODO: Consider adding synchonization (on mStream) for all operations // TODO: Consider adding synchonization (on stream) for all operations
// TODO: Is is a good thing that close/flush etc works on mStream? // TODO: Is is a good thing that close/flush etc works on stream?
// - Or should it rather just work on the views? // - Or should it rather just work on the views?
// - Allow multiple views? // - Allow multiple views?
@@ -190,8 +189,8 @@ public abstract class RandomAccessStream implements Seekable, DataInput, DataOut
} }
static final class OutputStreamView extends SeekableOutputStream { static final class OutputStreamView extends SeekableOutputStream {
// TODO: Consider adding synchonization (on mStream) for all operations // TODO: Consider adding synchonization (on stream) for all operations
// TODO: Is is a good thing that close/flush etc works on mStream? // TODO: Is is a good thing that close/flush etc works on stream?
// - Or should it rather just work on the views? // - Or should it rather just work on the views?
// - Allow multiple views? // - Allow multiple views?

View File

@@ -43,15 +43,15 @@ import java.util.Stack;
public abstract class SeekableInputStream extends InputStream implements Seekable { public abstract class SeekableInputStream extends InputStream implements Seekable {
// TODO: It's at the moment not possible to create subclasses outside this // TODO: It's at the moment not possible to create subclasses outside this
// package, as there's no access to mPosition. mPosition needs to be // package, as there's no access to position. position needs to be
// updated from the read/read/read methods... // updated from the read/read/read methods...
/** The stream position in this stream */ /** The stream position in this stream */
long mPosition; long position;
long mFlushedPosition; long flushedPosition;
boolean mClosed; boolean closed;
protected Stack<Long> mMarkedPositions = new Stack<Long>(); protected Stack<Long> markedPositions = new Stack<Long>();
/// InputStream overrides /// InputStream overrides
@Override @Override
@@ -70,8 +70,8 @@ public abstract class SeekableInputStream extends InputStream implements Seekabl
*/ */
@Override @Override
public final long skip(long pLength) throws IOException { public final long skip(long pLength) throws IOException {
long pos = mPosition; long pos = position;
if (pos + pLength < mFlushedPosition) { if (pos + pLength < flushedPosition) {
throw new IOException("position < flushedPosition"); throw new IOException("position < flushedPosition");
} }
@@ -79,7 +79,7 @@ public abstract class SeekableInputStream extends InputStream implements Seekabl
// to seek past end of stream // to seek past end of stream
seek(Math.min(pos + pLength, pos + available())); seek(Math.min(pos + pLength, pos + available()));
return mPosition - pos; return position - pos;
} }
@Override @Override
@@ -88,7 +88,7 @@ public abstract class SeekableInputStream extends InputStream implements Seekabl
// TODO: We don't really need to do this.. Is it a good idea? // TODO: We don't really need to do this.. Is it a good idea?
try { try {
flushBefore(Math.max(mPosition - pLimit, mFlushedPosition)); flushBefore(Math.max(position - pLimit, flushedPosition));
} }
catch (IOException ignore) { catch (IOException ignore) {
// Ignore, as it's not really critical // Ignore, as it's not really critical
@@ -111,29 +111,29 @@ public abstract class SeekableInputStream extends InputStream implements Seekabl
// NOTE: This is correct according to javax.imageio (IndexOutOfBoundsException), // NOTE: This is correct according to javax.imageio (IndexOutOfBoundsException),
// but it's kind of inconsistent with reset that throws IOException... // but it's kind of inconsistent with reset that throws IOException...
if (pPosition < mFlushedPosition) { if (pPosition < flushedPosition) {
throw new IndexOutOfBoundsException("position < flushedPosition"); throw new IndexOutOfBoundsException("position < flushedPosition");
} }
seekImpl(pPosition); seekImpl(pPosition);
mPosition = pPosition; position = pPosition;
} }
protected abstract void seekImpl(long pPosition) throws IOException; protected abstract void seekImpl(long pPosition) throws IOException;
public final void mark() { public final void mark() {
mMarkedPositions.push(mPosition); markedPositions.push(position);
} }
@Override @Override
public final void reset() throws IOException { public final void reset() throws IOException {
checkOpen(); checkOpen();
if (!mMarkedPositions.isEmpty()) { if (!markedPositions.isEmpty()) {
long newPos = mMarkedPositions.pop(); long newPos = markedPositions.pop();
// NOTE: This is correct according to javax.imageio (IOException), // NOTE: This is correct according to javax.imageio (IOException),
// but it's kind of inconsistent with seek that throws IndexOutOfBoundsException... // but it's kind of inconsistent with seek that throws IndexOutOfBoundsException...
if (newPos < mFlushedPosition) { if (newPos < flushedPosition) {
throw new IOException("Previous marked position has been discarded"); throw new IOException("Previous marked position has been discarded");
} }
@@ -150,7 +150,7 @@ public abstract class SeekableInputStream extends InputStream implements Seekabl
} }
public final void flushBefore(long pPosition) throws IOException { public final void flushBefore(long pPosition) throws IOException {
if (pPosition < mFlushedPosition) { if (pPosition < flushedPosition) {
throw new IndexOutOfBoundsException("position < flushedPosition"); throw new IndexOutOfBoundsException("position < flushedPosition");
} }
if (pPosition > getStreamPosition()) { if (pPosition > getStreamPosition()) {
@@ -158,7 +158,7 @@ public abstract class SeekableInputStream extends InputStream implements Seekabl
} }
checkOpen(); checkOpen();
flushBeforeImpl(pPosition); flushBeforeImpl(pPosition);
mFlushedPosition = pPosition; flushedPosition = pPosition;
} }
/** /**
@@ -172,21 +172,21 @@ public abstract class SeekableInputStream extends InputStream implements Seekabl
protected abstract void flushBeforeImpl(long pPosition) throws IOException; protected abstract void flushBeforeImpl(long pPosition) throws IOException;
public final void flush() throws IOException { public final void flush() throws IOException {
flushBefore(mFlushedPosition); flushBefore(flushedPosition);
} }
public final long getFlushedPosition() throws IOException { public final long getFlushedPosition() throws IOException {
checkOpen(); checkOpen();
return mFlushedPosition; return flushedPosition;
} }
public final long getStreamPosition() throws IOException { public final long getStreamPosition() throws IOException {
checkOpen(); checkOpen();
return mPosition; return position;
} }
protected final void checkOpen() throws IOException { protected final void checkOpen() throws IOException {
if (mClosed) { if (closed) {
throw new IOException("closed"); throw new IOException("closed");
} }
} }
@@ -194,7 +194,7 @@ public abstract class SeekableInputStream extends InputStream implements Seekabl
@Override @Override
public final void close() throws IOException { public final void close() throws IOException {
checkOpen(); checkOpen();
mClosed = true; closed = true;
closeImpl(); closeImpl();
} }
@@ -211,7 +211,7 @@ public abstract class SeekableInputStream extends InputStream implements Seekabl
*/ */
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
if (!mClosed) { if (!closed) {
try { try {
close(); close();
} }

View File

@@ -43,11 +43,11 @@ import java.util.Stack;
*/ */
public abstract class SeekableOutputStream extends OutputStream implements Seekable { public abstract class SeekableOutputStream extends OutputStream implements Seekable {
// TODO: Implement // TODO: Implement
long mPosition; long position;
long mFlushedPosition; long flushedPosition;
boolean mClosed; boolean closed;
protected Stack<Long> mMarkedPositions = new Stack<Long>(); protected Stack<Long> markedPositions = new Stack<Long>();
/// Outputstream overrides /// Outputstream overrides
@Override @Override
@@ -63,28 +63,28 @@ public abstract class SeekableOutputStream extends OutputStream implements Seeka
// TODO: This is correct according to javax.imageio (IndexOutOfBoundsException), // TODO: This is correct according to javax.imageio (IndexOutOfBoundsException),
// but it's inconsistent with reset that throws IOException... // but it's inconsistent with reset that throws IOException...
if (pPosition < mFlushedPosition) { if (pPosition < flushedPosition) {
throw new IndexOutOfBoundsException("position < flushedPosition!"); throw new IndexOutOfBoundsException("position < flushedPosition!");
} }
seekImpl(pPosition); seekImpl(pPosition);
mPosition = pPosition; position = pPosition;
} }
protected abstract void seekImpl(long pPosition) throws IOException; protected abstract void seekImpl(long pPosition) throws IOException;
public final void mark() { public final void mark() {
mMarkedPositions.push(mPosition); markedPositions.push(position);
} }
public final void reset() throws IOException { public final void reset() throws IOException {
checkOpen(); checkOpen();
if (!mMarkedPositions.isEmpty()) { if (!markedPositions.isEmpty()) {
long newPos = mMarkedPositions.pop(); long newPos = markedPositions.pop();
// TODO: This is correct according to javax.imageio (IOException), // TODO: This is correct according to javax.imageio (IOException),
// but it's inconsistent with seek that throws IndexOutOfBoundsException... // but it's inconsistent with seek that throws IndexOutOfBoundsException...
if (newPos < mFlushedPosition) { if (newPos < flushedPosition) {
throw new IOException("Previous marked position has been discarded!"); throw new IOException("Previous marked position has been discarded!");
} }
@@ -93,7 +93,7 @@ public abstract class SeekableOutputStream extends OutputStream implements Seeka
} }
public final void flushBefore(long pPosition) throws IOException { public final void flushBefore(long pPosition) throws IOException {
if (pPosition < mFlushedPosition) { if (pPosition < flushedPosition) {
throw new IndexOutOfBoundsException("position < flushedPosition!"); throw new IndexOutOfBoundsException("position < flushedPosition!");
} }
if (pPosition > getStreamPosition()) { if (pPosition > getStreamPosition()) {
@@ -101,28 +101,28 @@ public abstract class SeekableOutputStream extends OutputStream implements Seeka
} }
checkOpen(); checkOpen();
flushBeforeImpl(pPosition); flushBeforeImpl(pPosition);
mFlushedPosition = pPosition; flushedPosition = pPosition;
} }
protected abstract void flushBeforeImpl(long pPosition) throws IOException; protected abstract void flushBeforeImpl(long pPosition) throws IOException;
@Override @Override
public final void flush() throws IOException { public final void flush() throws IOException {
flushBefore(mFlushedPosition); flushBefore(flushedPosition);
} }
public final long getFlushedPosition() throws IOException { public final long getFlushedPosition() throws IOException {
checkOpen(); checkOpen();
return mFlushedPosition; return flushedPosition;
} }
public final long getStreamPosition() throws IOException { public final long getStreamPosition() throws IOException {
checkOpen(); checkOpen();
return mPosition; return position;
} }
protected final void checkOpen() throws IOException { protected final void checkOpen() throws IOException {
if (mClosed) { if (closed) {
throw new IOException("closed"); throw new IOException("closed");
} }
} }
@@ -130,7 +130,7 @@ public abstract class SeekableOutputStream extends OutputStream implements Seeka
@Override @Override
public final void close() throws IOException { public final void close() throws IOException {
checkOpen(); checkOpen();
mClosed = true; closed = true;
closeImpl(); closeImpl();
} }

View File

@@ -28,6 +28,8 @@
package com.twelvemonkeys.io; package com.twelvemonkeys.io;
import com.twelvemonkeys.lang.Validate;
import java.io.StringReader; import java.io.StringReader;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
@@ -42,13 +44,13 @@ import java.io.Reader;
*/ */
public class StringArrayReader extends StringReader { public class StringArrayReader extends StringReader {
private StringReader mCurrent; private StringReader current;
private String[] mStrings; private String[] strings;
protected final Object mLock; protected final Object finalLock;
private int mCurrentSting; private int currentSting;
private int mMarkedString; private int markedString;
private int mMark; private int mark;
private int mNext; private int next;
/** /**
* Create a new string array reader. * Create a new string array reader.
@@ -57,28 +59,28 @@ public class StringArrayReader extends StringReader {
*/ */
public StringArrayReader(final String[] pStrings) { public StringArrayReader(final String[] pStrings) {
super(""); super("");
if (pStrings == null) {
throw new NullPointerException("strings == null");
}
mLock = lock = pStrings; // NOTE: It's ok to sync on pStrings, as the Validate.notNull(pStrings, "strings");
finalLock = lock = pStrings; // NOTE: It's ok to sync on pStrings, as the
// reference can't change, only it's elements // reference can't change, only it's elements
mStrings = pStrings.clone(); // Defensive copy for content strings = pStrings.clone(); // Defensive copy for content
nextReader(); nextReader();
} }
protected final Reader nextReader() { protected final Reader nextReader() {
if (mCurrentSting >= mStrings.length) { if (currentSting >= strings.length) {
mCurrent = new EmptyReader(); current = new EmptyReader();
} }
else { else {
mCurrent = new StringReader(mStrings[mCurrentSting++]); current = new StringReader(strings[currentSting++]);
} }
// NOTE: Reset mNext for every reader, and record marked reader in mark/reset methods!
mNext = 0; // NOTE: Reset next for every reader, and record marked reader in mark/reset methods!
next = 0;
return mCurrent; return current;
} }
/** /**
@@ -87,15 +89,15 @@ public class StringArrayReader extends StringReader {
* @throws IOException if the stream is closed * @throws IOException if the stream is closed
*/ */
protected final void ensureOpen() throws IOException { protected final void ensureOpen() throws IOException {
if (mStrings == null) { if (strings == null) {
throw new IOException("Stream closed"); throw new IOException("Stream closed");
} }
} }
public void close() { public void close() {
super.close(); super.close();
mStrings = null; strings = null;
mCurrent.close(); current.close();
} }
public void mark(int pReadLimit) throws IOException { public void mark(int pReadLimit) throws IOException {
@@ -103,29 +105,29 @@ public class StringArrayReader extends StringReader {
throw new IllegalArgumentException("Read limit < 0"); throw new IllegalArgumentException("Read limit < 0");
} }
synchronized (mLock) { synchronized (finalLock) {
ensureOpen(); ensureOpen();
mMark = mNext; mark = next;
mMarkedString = mCurrentSting; markedString = currentSting;
mCurrent.mark(pReadLimit); current.mark(pReadLimit);
} }
} }
public void reset() throws IOException { public void reset() throws IOException {
synchronized (mLock) { synchronized (finalLock) {
ensureOpen(); ensureOpen();
if (mCurrentSting != mMarkedString) { if (currentSting != markedString) {
mCurrentSting = mMarkedString - 1; currentSting = markedString - 1;
nextReader(); nextReader();
mCurrent.skip(mMark); current.skip(mark);
} }
else { else {
mCurrent.reset(); current.reset();
} }
mNext = mMark; next = mark;
} }
} }
@@ -134,49 +136,49 @@ public class StringArrayReader extends StringReader {
} }
public int read() throws IOException { public int read() throws IOException {
synchronized (mLock) { synchronized (finalLock) {
int read = mCurrent.read(); int read = current.read();
if (read < 0 && mCurrentSting < mStrings.length) { if (read < 0 && currentSting < strings.length) {
nextReader(); nextReader();
return read(); // In case of empty strings return read(); // In case of empty strings
} }
mNext++; next++;
return read; return read;
} }
} }
public int read(char pBuffer[], int pOffset, int pLength) throws IOException { public int read(char pBuffer[], int pOffset, int pLength) throws IOException {
synchronized (mLock) { synchronized (finalLock) {
int read = mCurrent.read(pBuffer, pOffset, pLength); int read = current.read(pBuffer, pOffset, pLength);
if (read < 0 && mCurrentSting < mStrings.length) { if (read < 0 && currentSting < strings.length) {
nextReader(); nextReader();
return read(pBuffer, pOffset, pLength); // In case of empty strings return read(pBuffer, pOffset, pLength); // In case of empty strings
} }
mNext += read; next += read;
return read; return read;
} }
} }
public boolean ready() throws IOException { public boolean ready() throws IOException {
return mCurrent.ready(); return current.ready();
} }
public long skip(long pChars) throws IOException { public long skip(long pChars) throws IOException {
synchronized (mLock) { synchronized (finalLock) {
long skipped = mCurrent.skip(pChars); long skipped = current.skip(pChars);
if (skipped == 0 && mCurrentSting < mStrings.length) { if (skipped == 0 && currentSting < strings.length) {
nextReader(); nextReader();
return skip(pChars); return skip(pChars);
} }
mNext += skipped; next += skipped;
return skipped; return skipped;
} }

View File

@@ -43,8 +43,8 @@ import java.io.InputStream;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/SubStream.java#2 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/SubStream.java#2 $
*/ */
public final class SubStream extends FilterInputStream { public final class SubStream extends FilterInputStream {
private long mLeft; private long bytesLeft;
private int mMarkLimit; private int markLimit;
/** /**
* Creates a {@code SubStream} of the given {@code pStream}. * Creates a {@code SubStream} of the given {@code pStream}.
@@ -54,7 +54,7 @@ public final class SubStream extends FilterInputStream {
*/ */
public SubStream(final InputStream pStream, final long pLength) { public SubStream(final InputStream pStream, final long pLength) {
super(Validate.notNull(pStream, "stream")); super(Validate.notNull(pStream, "stream"));
mLeft = pLength; bytesLeft = pLength;
} }
/** /**
@@ -64,32 +64,32 @@ public final class SubStream extends FilterInputStream {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
// NOTE: Do not close the underlying stream // NOTE: Do not close the underlying stream
while (mLeft > 0) { while (bytesLeft > 0) {
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
skip(mLeft); skip(bytesLeft);
} }
} }
@Override @Override
public int available() throws IOException { public int available() throws IOException {
return (int) Math.min(super.available(), mLeft); return (int) Math.min(super.available(), bytesLeft);
} }
@Override @Override
public void mark(int pReadLimit) { public void mark(int pReadLimit) {
super.mark(pReadLimit);// This either succeeds or does nothing... super.mark(pReadLimit);// This either succeeds or does nothing...
mMarkLimit = pReadLimit; markLimit = pReadLimit;
} }
@Override @Override
public void reset() throws IOException { public void reset() throws IOException {
super.reset();// This either succeeds or throws IOException super.reset();// This either succeeds or throws IOException
mLeft += mMarkLimit; bytesLeft += markLimit;
} }
@Override @Override
public int read() throws IOException { public int read() throws IOException {
if (mLeft-- <= 0) { if (bytesLeft-- <= 0) {
return -1; return -1;
} }
return super.read(); return super.read();
@@ -102,12 +102,12 @@ public final class SubStream extends FilterInputStream {
@Override @Override
public int read(final byte[] pBytes, final int pOffset, final int pLength) throws IOException { public int read(final byte[] pBytes, final int pOffset, final int pLength) throws IOException {
if (mLeft <= 0) { if (bytesLeft <= 0) {
return -1; return -1;
} }
int read = super.read(pBytes, pOffset, (int) findMaxLen(pLength)); int read = super.read(pBytes, pOffset, (int) findMaxLen(pLength));
mLeft = read < 0 ? 0 : mLeft - read; bytesLeft = read < 0 ? 0 : bytesLeft - read;
return read; return read;
} }
@@ -118,8 +118,8 @@ public final class SubStream extends FilterInputStream {
* @return the maximum number of bytes to read * @return the maximum number of bytes to read
*/ */
private long findMaxLen(long pLength) { private long findMaxLen(long pLength) {
if (mLeft < pLength) { if (bytesLeft < pLength) {
return (int) Math.max(mLeft, 0); return (int) Math.max(bytesLeft, 0);
} }
else { else {
return pLength; return pLength;
@@ -129,7 +129,7 @@ public final class SubStream extends FilterInputStream {
@Override @Override
public long skip(long pLength) throws IOException { public long skip(long pLength) throws IOException {
long skipped = super.skip(findMaxLen(pLength));// Skips 0 or more, never -1 long skipped = super.skip(findMaxLen(pLength));// Skips 0 or more, never -1
mLeft -= skipped; bytesLeft -= skipped;
return skipped; return skipped;
} }
} }

View File

@@ -50,7 +50,8 @@ final class Win32Lnk extends File {
(byte) 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'F' (byte) 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'F'
}; };
private final File mTarget; private final File target;
private static final int FLAG_ITEM_ID_LIST = 0x01; private static final int FLAG_ITEM_ID_LIST = 0x01;
private static final int FLAG_FILE_LOC_INFO = 0x02; private static final int FLAG_FILE_LOC_INFO = 0x02;
private static final int FLAG_DESC_STRING = 0x04; private static final int FLAG_DESC_STRING = 0x04;
@@ -65,10 +66,10 @@ final class Win32Lnk extends File {
File target = parse(this); File target = parse(this);
if (target == this) { if (target == this) {
// NOTE: This is a workaround // NOTE: This is a workaround
// mTarget = this causes infinite loops in some methods // target = this causes infinite loops in some methods
target = new File(pPath); target = new File(pPath);
} }
mTarget = target; this.target = target;
} }
Win32Lnk(final File pPath) throws IOException { Win32Lnk(final File pPath) throws IOException {
@@ -336,24 +337,24 @@ final class Win32Lnk extends File {
*/ */
public File getTarget() { public File getTarget() {
return mTarget; return target;
} }
// java.io.File overrides below // java.io.File overrides below
@Override @Override
public boolean isDirectory() { public boolean isDirectory() {
return mTarget.isDirectory(); return target.isDirectory();
} }
@Override @Override
public boolean canRead() { public boolean canRead() {
return mTarget.canRead(); return target.canRead();
} }
@Override @Override
public boolean canWrite() { public boolean canWrite() {
return mTarget.canWrite(); return target.canWrite();
} }
// NOTE: equals is implemented using compareto == 0 // NOTE: equals is implemented using compareto == 0
@@ -362,7 +363,7 @@ final class Win32Lnk extends File {
// TODO: Verify this // TODO: Verify this
// Probably not a good idea, as it IS NOT THE SAME file // Probably not a good idea, as it IS NOT THE SAME file
// It's probably better to not override // It's probably better to not override
return mTarget.compareTo(pathname); return target.compareTo(pathname);
} }
*/ */
@@ -375,7 +376,7 @@ final class Win32Lnk extends File {
@Override @Override
public boolean exists() { public boolean exists() {
return mTarget.exists(); return target.exists();
} }
// A .lnk may be absolute // A .lnk may be absolute
@@ -385,12 +386,12 @@ final class Win32Lnk extends File {
// Theses should be resolved according to the API (for Unix). // Theses should be resolved according to the API (for Unix).
@Override @Override
public File getCanonicalFile() throws IOException { public File getCanonicalFile() throws IOException {
return mTarget.getCanonicalFile(); return target.getCanonicalFile();
} }
@Override @Override
public String getCanonicalPath() throws IOException { public String getCanonicalPath() throws IOException {
return mTarget.getCanonicalPath(); return target.getCanonicalPath();
} }
//public String getName() { //public String getName() {
@@ -402,47 +403,47 @@ final class Win32Lnk extends File {
// public boolean isAbsolute() { // public boolean isAbsolute() {
@Override @Override
public boolean isFile() { public boolean isFile() {
return mTarget.isFile(); return target.isFile();
} }
@Override @Override
public boolean isHidden() { public boolean isHidden() {
return mTarget.isHidden(); return target.isHidden();
} }
@Override @Override
public long lastModified() { public long lastModified() {
return mTarget.lastModified(); return target.lastModified();
} }
@Override @Override
public long length() { public long length() {
return mTarget.length(); return target.length();
} }
@Override @Override
public String[] list() { public String[] list() {
return mTarget.list(); return target.list();
} }
@Override @Override
public String[] list(final FilenameFilter filter) { public String[] list(final FilenameFilter filter) {
return mTarget.list(filter); return target.list(filter);
} }
@Override @Override
public File[] listFiles() { public File[] listFiles() {
return Win32File.wrap(mTarget.listFiles()); return Win32File.wrap(target.listFiles());
} }
@Override @Override
public File[] listFiles(final FileFilter filter) { public File[] listFiles(final FileFilter filter) {
return Win32File.wrap(mTarget.listFiles(filter)); return Win32File.wrap(target.listFiles(filter));
} }
@Override @Override
public File[] listFiles(final FilenameFilter filter) { public File[] listFiles(final FilenameFilter filter) {
return Win32File.wrap(mTarget.listFiles(filter)); return Win32File.wrap(target.listFiles(filter));
} }
// Makes no sense, does it? // Makes no sense, does it?
@@ -454,19 +455,19 @@ final class Win32Lnk extends File {
@Override @Override
public boolean setLastModified(long time) { public boolean setLastModified(long time) {
return mTarget.setLastModified(time); return target.setLastModified(time);
} }
@Override @Override
public boolean setReadOnly() { public boolean setReadOnly() {
return mTarget.setReadOnly(); return target.setReadOnly();
} }
@Override @Override
public String toString() { public String toString() {
if (mTarget.equals(this)) { if (target.equals(this)) {
return super.toString(); return super.toString();
} }
return super.toString() + " -> " + mTarget.toString(); return super.toString() + " -> " + target.toString();
} }
} }

View File

@@ -51,10 +51,11 @@ import java.nio.CharBuffer;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/WriterOutputStream.java#2 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/WriterOutputStream.java#2 $
*/ */
public class WriterOutputStream extends OutputStream { public class WriterOutputStream extends OutputStream {
protected Writer mWriter; protected Writer writer;
final protected Decoder mDecoder; final protected Decoder decoder;
final ByteArrayOutputStream mBufferStream = new FastByteArrayOutputStream(1024); final ByteArrayOutputStream bufferStream = new FastByteArrayOutputStream(1024);
private volatile boolean mIsFlushing = false; // Ugly but critical...
private volatile boolean isFlushing = false; // Ugly but critical...
private static final boolean NIO_AVAILABLE = isNIOAvailable(); private static final boolean NIO_AVAILABLE = isNIOAvailable();
@@ -71,8 +72,8 @@ public class WriterOutputStream extends OutputStream {
} }
public WriterOutputStream(final Writer pWriter, final String pCharset) { public WriterOutputStream(final Writer pWriter, final String pCharset) {
mWriter = pWriter; writer = pWriter;
mDecoder = getDecoder(pCharset); decoder = getDecoder(pCharset);
} }
public WriterOutputStream(final Writer pWriter) { public WriterOutputStream(final Writer pWriter) {
@@ -94,14 +95,14 @@ public class WriterOutputStream extends OutputStream {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
flush(); flush();
mWriter.close(); writer.close();
mWriter = null; writer = null;
} }
@Override @Override
public void flush() throws IOException { public void flush() throws IOException {
flushBuffer(); flushBuffer();
mWriter.flush(); writer.flush();
} }
@Override @Override
@@ -115,22 +116,22 @@ public class WriterOutputStream extends OutputStream {
@Override @Override
public final void write(byte[] pBytes, int pOffset, int pLength) throws IOException { public final void write(byte[] pBytes, int pOffset, int pLength) throws IOException {
flushBuffer(); flushBuffer();
mDecoder.decodeTo(mWriter, pBytes, pOffset, pLength); decoder.decodeTo(writer, pBytes, pOffset, pLength);
} }
@Override @Override
public final void write(int pByte) { public final void write(int pByte) {
// TODO: Is it possible to know if this is a good place in the stream to // TODO: Is it possible to know if this is a good place in the stream to
// flush? It might be in the middle of a multi-byte encoded character.. // flush? It might be in the middle of a multi-byte encoded character..
mBufferStream.write(pByte); bufferStream.write(pByte);
} }
private void flushBuffer() throws IOException { private void flushBuffer() throws IOException {
if (!mIsFlushing && mBufferStream.size() > 0) { if (!isFlushing && bufferStream.size() > 0) {
mIsFlushing = true; isFlushing = true;
mBufferStream.writeTo(this); // NOTE: Avoids cloning buffer array bufferStream.writeTo(this); // NOTE: Avoids cloning buffer array
mBufferStream.reset(); bufferStream.reset();
mIsFlushing = false; isFlushing = false;
} }
} }
@@ -138,7 +139,7 @@ public class WriterOutputStream extends OutputStream {
public static void main(String[] pArgs) throws IOException { public static void main(String[] pArgs) throws IOException {
int iterations = 1000000; int iterations = 1000000;
byte[] bytes = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> klashf lkash ljah lhaaklhghdfgu ksd".getBytes("UTF-8"); byte[] bytes = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> klashf lkash ljah lhaaklhghdfgu ksd".getBytes("UTF-8");
Decoder d; Decoder d;
long start; long start;

View File

@@ -41,12 +41,12 @@ import java.io.InputStream;
*/ */
// TODO: Move to other package or make public // TODO: Move to other package or make public
abstract class AbstractRLEDecoder implements Decoder { abstract class AbstractRLEDecoder implements Decoder {
protected final byte[] mRow; protected final byte[] row;
protected final int mWidth; protected final int width;
protected int mSrcX; protected int srcX;
protected int mSrcY; protected int srcY;
protected int mDstX; protected int dstX;
protected int mDstY; protected int dstY;
/** /**
* Creates an RLEDecoder. As RLE encoded BMP's may contain x and y deltas, * Creates an RLEDecoder. As RLE encoded BMP's may contain x and y deltas,
@@ -56,21 +56,21 @@ abstract class AbstractRLEDecoder implements Decoder {
* @param pHeight heigth of the image * @param pHeight heigth of the image
*/ */
AbstractRLEDecoder(int pWidth, int pHeight) { AbstractRLEDecoder(int pWidth, int pHeight) {
mWidth = pWidth; width = pWidth;
int bytesPerRow = mWidth; int bytesPerRow = width;
int mod = bytesPerRow % 4; int mod = bytesPerRow % 4;
if (mod != 0) { if (mod != 0) {
bytesPerRow += 4 - mod; bytesPerRow += 4 - mod;
} }
mRow = new byte[bytesPerRow]; row = new byte[bytesPerRow];
mSrcX = 0; srcX = 0;
mSrcY = pHeight - 1; srcY = pHeight - 1;
mDstX = mSrcX; dstX = srcX;
mDstY = mSrcY; dstY = srcY;
} }
/** /**
@@ -95,26 +95,26 @@ abstract class AbstractRLEDecoder implements Decoder {
public final int decode(InputStream pStream, byte[] pBuffer) throws IOException { public final int decode(InputStream pStream, byte[] pBuffer) throws IOException {
int decoded = 0; int decoded = 0;
while (decoded < pBuffer.length && mDstY >= 0) { while (decoded < pBuffer.length && dstY >= 0) {
// NOTE: Decode only full rows, don't decode if y delta // NOTE: Decode only full rows, don't decode if y delta
if (mDstX == 0 && mSrcY == mDstY) { if (dstX == 0 && srcY == dstY) {
decodeRow(pStream); decodeRow(pStream);
} }
int length = Math.min(mRow.length - mDstX, pBuffer.length - decoded); int length = Math.min(row.length - dstX, pBuffer.length - decoded);
System.arraycopy(mRow, mDstX, pBuffer, decoded, length); System.arraycopy(row, dstX, pBuffer, decoded, length);
mDstX += length; dstX += length;
decoded += length; decoded += length;
if (mDstX == mRow.length) { if (dstX == row.length) {
mDstX = 0; dstX = 0;
mDstY--; dstY--;
// NOTE: If src Y is < dst Y, we have a delta, and have to fill the // NOTE: If src Y is < dst Y, we have a delta, and have to fill the
// gap with zero-bytes // gap with zero-bytes
if (mDstY > mSrcY) { if (dstY > srcY) {
for (int i = 0; i < mRow.length; i++) { for (int i = 0; i < row.length; i++) {
mRow[i] = 0x00; row[i] = 0x00;
} }
} }
} }

View File

@@ -61,9 +61,9 @@ public final class Base64Decoder implements Decoder {
final static byte[] PEM_CONVERT_ARRAY; final static byte[] PEM_CONVERT_ARRAY;
private byte[] mDecodeBuffer = new byte[4]; private byte[] decodeBuffer = new byte[4];
private ByteArrayOutputStream mWrapped; private ByteArrayOutputStream wrapped;
private Object mWrappedObject; private Object wrappedObject;
static { static {
PEM_CONVERT_ARRAY = new byte[256]; PEM_CONVERT_ARRAY = new byte[256];
@@ -116,8 +116,8 @@ public final class Base64Decoder implements Decoder {
} }
} while (read == 10 || read == 13); } while (read == 10 || read == 13);
mDecodeBuffer[0] = (byte) read; decodeBuffer[0] = (byte) read;
read = readFully(pInput, mDecodeBuffer, 1, pLength - 1); read = readFully(pInput, decodeBuffer, 1, pLength - 1);
if (read == -1) { if (read == -1) {
return false; return false;
@@ -125,24 +125,24 @@ public final class Base64Decoder implements Decoder {
int length = pLength; int length = pLength;
if (length > 3 && mDecodeBuffer[3] == 61) { if (length > 3 && decodeBuffer[3] == 61) {
length = 3; length = 3;
} }
if (length > 2 && mDecodeBuffer[2] == 61) { if (length > 2 && decodeBuffer[2] == 61) {
length = 2; length = 2;
} }
switch (length) { switch (length) {
case 4: case 4:
byte3 = PEM_CONVERT_ARRAY[mDecodeBuffer[3] & 255]; byte3 = PEM_CONVERT_ARRAY[decodeBuffer[3] & 255];
// fall through // fall through
case 3: case 3:
byte2 = PEM_CONVERT_ARRAY[mDecodeBuffer[2] & 255]; byte2 = PEM_CONVERT_ARRAY[decodeBuffer[2] & 255];
// fall through // fall through
case 2: case 2:
byte1 = PEM_CONVERT_ARRAY[mDecodeBuffer[1] & 255]; byte1 = PEM_CONVERT_ARRAY[decodeBuffer[1] & 255];
byte0 = PEM_CONVERT_ARRAY[mDecodeBuffer[0] & 255]; byte0 = PEM_CONVERT_ARRAY[decodeBuffer[0] & 255];
// fall through // fall through
default: default:
switch (length) { switch (length) {
@@ -185,15 +185,15 @@ public final class Base64Decoder implements Decoder {
} }
public int decode(final InputStream pStream, final byte[] pBuffer) throws IOException { public int decode(final InputStream pStream, final byte[] pBuffer) throws IOException {
if (mWrappedObject != pBuffer) { if (wrappedObject != pBuffer) {
// NOTE: Array not cloned in FastByteArrayOutputStream // NOTE: Array not cloned in FastByteArrayOutputStream
mWrapped = new FastByteArrayOutputStream(pBuffer); wrapped = new FastByteArrayOutputStream(pBuffer);
mWrappedObject = pBuffer; wrappedObject = pBuffer;
} }
mWrapped.reset(); // NOTE: This only resets count to 0 wrapped.reset(); // NOTE: This only resets count to 0
decodeBuffer(pStream, mWrapped, pBuffer.length); decodeBuffer(pStream, wrapped, pBuffer.length);
return mWrapped.size(); return wrapped.size();
} }
} }

View File

@@ -44,10 +44,10 @@ import java.io.FilterInputStream;
*/ */
public final class DecoderStream extends FilterInputStream { public final class DecoderStream extends FilterInputStream {
protected int mBufferPos; protected int bufferPos;
protected int mBufferLimit; protected int bufferLimit;
protected final byte[] mBuffer; protected final byte[] buffer;
protected final Decoder mDecoder; protected final Decoder decoder;
/** /**
* Creates a new decoder stream and chains it to the * Creates a new decoder stream and chains it to the
@@ -76,26 +76,26 @@ public final class DecoderStream extends FilterInputStream {
*/ */
public DecoderStream(final InputStream pStream, final Decoder pDecoder, final int pBufferSize) { public DecoderStream(final InputStream pStream, final Decoder pDecoder, final int pBufferSize) {
super(pStream); super(pStream);
mDecoder = pDecoder; decoder = pDecoder;
mBuffer = new byte[pBufferSize]; buffer = new byte[pBufferSize];
mBufferPos = 0; bufferPos = 0;
mBufferLimit = 0; bufferLimit = 0;
} }
public int available() throws IOException { public int available() throws IOException {
return mBufferLimit - mBufferPos + super.available(); return bufferLimit - bufferPos + super.available();
} }
public int read() throws IOException { public int read() throws IOException {
if (mBufferPos == mBufferLimit) { if (bufferPos == bufferLimit) {
mBufferLimit = fill(); bufferLimit = fill();
} }
if (mBufferLimit < 0) { if (bufferLimit < 0) {
return -1; return -1;
} }
return mBuffer[mBufferPos++] & 0xff; return buffer[bufferPos++] & 0xff;
} }
public int read(final byte pBytes[]) throws IOException { public int read(final byte pBytes[]) throws IOException {
@@ -115,7 +115,7 @@ public final class DecoderStream extends FilterInputStream {
} }
// End of file? // End of file?
if ((mBufferLimit - mBufferPos) < 0) { if ((bufferLimit - bufferPos) < 0) {
return -1; return -1;
} }
@@ -124,21 +124,21 @@ public final class DecoderStream extends FilterInputStream {
int off = pOffset; int off = pOffset;
while (pLength > count) { while (pLength > count) {
int avail = mBufferLimit - mBufferPos; int avail = bufferLimit - bufferPos;
if (avail <= 0) { if (avail <= 0) {
mBufferLimit = fill(); bufferLimit = fill();
if (mBufferLimit < 0) { if (bufferLimit < 0) {
break; break;
} }
} }
// Copy as many bytes as possible // Copy as many bytes as possible
int dstLen = Math.min(pLength - count, avail); int dstLen = Math.min(pLength - count, avail);
System.arraycopy(mBuffer, mBufferPos, pBytes, off, dstLen); System.arraycopy(buffer, bufferPos, pBytes, off, dstLen);
mBufferPos += dstLen; bufferPos += dstLen;
// Update offset (rest) // Update offset (rest)
off += dstLen; off += dstLen;
@@ -152,7 +152,7 @@ public final class DecoderStream extends FilterInputStream {
public long skip(final long pLength) throws IOException { public long skip(final long pLength) throws IOException {
// End of file? // End of file?
if (mBufferLimit - mBufferPos < 0) { if (bufferLimit - bufferPos < 0) {
return 0; return 0;
} }
@@ -160,12 +160,12 @@ public final class DecoderStream extends FilterInputStream {
long total = 0; long total = 0;
while (total < pLength) { while (total < pLength) {
int avail = mBufferLimit - mBufferPos; int avail = bufferLimit - bufferPos;
if (avail == 0) { if (avail == 0) {
mBufferLimit = fill(); bufferLimit = fill();
if (mBufferLimit < 0) { if (bufferLimit < 0) {
break; break;
} }
} }
@@ -174,7 +174,7 @@ public final class DecoderStream extends FilterInputStream {
// an int, so the cast is safe // an int, so the cast is safe
int skipped = (int) Math.min(pLength - total, avail); int skipped = (int) Math.min(pLength - total, avail);
mBufferPos += skipped; // Just skip these bytes bufferPos += skipped; // Just skip these bytes
total += skipped; total += skipped;
} }
@@ -190,19 +190,19 @@ public final class DecoderStream extends FilterInputStream {
* @throws IOException if an I/O error occurs * @throws IOException if an I/O error occurs
*/ */
protected int fill() throws IOException { protected int fill() throws IOException {
int read = mDecoder.decode(in, mBuffer); int read = decoder.decode(in, buffer);
// TODO: Enforce this in test case, leave here to aid debugging // TODO: Enforce this in test case, leave here to aid debugging
if (read > mBuffer.length) { if (read > buffer.length) {
throw new AssertionError( throw new AssertionError(
String.format( String.format(
"Decode beyond buffer (%d): %d (using %s decoder)", "Decode beyond buffer (%d): %d (using %s decoder)",
mBuffer.length, read, mDecoder.getClass().getName() buffer.length, read, decoder.getClass().getName()
) )
); );
} }
mBufferPos = 0; bufferPos = 0;
if (read == 0) { if (read == 0) {
return -1; return -1;

View File

@@ -57,8 +57,7 @@ public interface Encoder {
* *
* @throws java.io.IOException if an I/O error occurs * @throws java.io.IOException if an I/O error occurs
*/ */
void encode(OutputStream pStream, byte[] pBuffer, int pOffset, int pLength) void encode(OutputStream pStream, byte[] pBuffer, int pOffset, int pLength) throws IOException;
throws IOException;
//TODO: int requiredBufferSize(): -1 == any, otherwise, use this buffer size //TODO: int requiredBufferSize(): -1 == any, otherwise, use this buffer size
// void flush()? // void flush()?

View File

@@ -44,11 +44,11 @@ import java.io.IOException;
*/ */
public final class EncoderStream extends FilterOutputStream { public final class EncoderStream extends FilterOutputStream {
protected final Encoder mEncoder; protected final Encoder encoder;
private final boolean mFlushOnWrite; private final boolean flushOnWrite;
protected int mBufferPos; protected int bufferPos;
protected final byte[] mBuffer; protected final byte[] buffer;
/** /**
* Creates an output stream filter built on top of the specified * Creates an output stream filter built on top of the specified
@@ -73,11 +73,11 @@ public final class EncoderStream extends FilterOutputStream {
public EncoderStream(final OutputStream pStream, final Encoder pEncoder, final boolean pFlushOnWrite) { public EncoderStream(final OutputStream pStream, final Encoder pEncoder, final boolean pFlushOnWrite) {
super(pStream); super(pStream);
mEncoder = pEncoder; encoder = pEncoder;
mFlushOnWrite = pFlushOnWrite; flushOnWrite = pFlushOnWrite;
mBuffer = new byte[1024]; buffer = new byte[1024];
mBufferPos = 0; bufferPos = 0;
} }
public void close() throws IOException { public void close() throws IOException {
@@ -91,12 +91,12 @@ public final class EncoderStream extends FilterOutputStream {
} }
private void encodeBuffer() throws IOException { private void encodeBuffer() throws IOException {
if (mBufferPos != 0) { if (bufferPos != 0) {
// Make sure all remaining data in buffer is written to the stream // Make sure all remaining data in buffer is written to the stream
mEncoder.encode(out, mBuffer, 0, mBufferPos); encoder.encode(out, buffer, 0, bufferPos);
// Reset buffer // Reset buffer
mBufferPos = 0; bufferPos = 0;
} }
} }
@@ -109,27 +109,27 @@ public final class EncoderStream extends FilterOutputStream {
// that the encoder can't buffer. In that case, the encoder should probably // that the encoder can't buffer. In that case, the encoder should probably
// tell the EncoderStream how large buffer it prefers... // tell the EncoderStream how large buffer it prefers...
public void write(final byte[] pBytes, final int pOffset, final int pLength) throws IOException { public void write(final byte[] pBytes, final int pOffset, final int pLength) throws IOException {
if (!mFlushOnWrite && mBufferPos + pLength < mBuffer.length) { if (!flushOnWrite && bufferPos + pLength < buffer.length) {
// Buffer data // Buffer data
System.arraycopy(pBytes, pOffset, mBuffer, mBufferPos, pLength); System.arraycopy(pBytes, pOffset, buffer, bufferPos, pLength);
mBufferPos += pLength; bufferPos += pLength;
} }
else { else {
// Encode data already in the buffer // Encode data already in the buffer
if (mBufferPos != 0) { if (bufferPos != 0) {
encodeBuffer(); encodeBuffer();
} }
// Encode rest without buffering // Encode rest without buffering
mEncoder.encode(out, pBytes, pOffset, pLength); encoder.encode(out, pBytes, pOffset, pLength);
} }
} }
public void write(final int pByte) throws IOException { public void write(final int pByte) throws IOException {
if (mBufferPos >= mBuffer.length - 1) { if (bufferPos >= buffer.length - 1) {
encodeBuffer(); // Resets mBufferPos to 0 encodeBuffer(); // Resets bufferPos to 0
} }
mBuffer[mBufferPos++] = (byte) pByte; buffer[bufferPos++] = (byte) pByte;
} }
} }

View File

@@ -46,11 +46,11 @@ import java.io.EOFException;
*/ */
public final class PackBits16Decoder implements Decoder { public final class PackBits16Decoder implements Decoder {
// TODO: Refactor this into an option for the PackBitsDecoder? // TODO: Refactor this into an option for the PackBitsDecoder?
private final boolean mDisableNoop; private final boolean disableNoop;
private int mLeftOfRun; private int leftOfRun;
private boolean mSplitRun; private boolean splitRun;
private boolean mEOF; private boolean reachedEOF;
/** /**
* Creates a {@code PackBitsDecoder}. * Creates a {@code PackBitsDecoder}.
@@ -71,7 +71,7 @@ public final class PackBits16Decoder implements Decoder {
* @param pDisableNoop {@code true} if {@code -128} should be treated as a compressed run, and not a no-op * @param pDisableNoop {@code true} if {@code -128} should be treated as a compressed run, and not a no-op
*/ */
public PackBits16Decoder(final boolean pDisableNoop) { public PackBits16Decoder(final boolean pDisableNoop) {
mDisableNoop = pDisableNoop; disableNoop = pDisableNoop;
} }
/** /**
@@ -85,7 +85,7 @@ public final class PackBits16Decoder implements Decoder {
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public int decode(final InputStream pStream, final byte[] pBuffer) throws IOException { public int decode(final InputStream pStream, final byte[] pBuffer) throws IOException {
if (mEOF) { if (reachedEOF) {
return -1; return -1;
} }
@@ -95,16 +95,16 @@ public final class PackBits16Decoder implements Decoder {
while (read < max) { while (read < max) {
int n; int n;
if (mSplitRun) { if (splitRun) {
// Continue run // Continue run
n = mLeftOfRun; n = leftOfRun;
mSplitRun = false; splitRun = false;
} }
else { else {
// Start new run // Start new run
int b = pStream.read(); int b = pStream.read();
if (b < 0) { if (b < 0) {
mEOF = true; reachedEOF = true;
break; break;
} }
n = (byte) b; n = (byte) b;
@@ -112,13 +112,13 @@ public final class PackBits16Decoder implements Decoder {
// Split run at or before max // Split run at or before max
if (n >= 0 && 2 * (n + 1) + read > max) { if (n >= 0 && 2 * (n + 1) + read > max) {
mLeftOfRun = n; leftOfRun = n;
mSplitRun = true; splitRun = true;
break; break;
} }
else if (n < 0 && 2 * (-n + 1) + read > max) { else if (n < 0 && 2 * (-n + 1) + read > max) {
mLeftOfRun = n; leftOfRun = n;
mSplitRun = true; splitRun = true;
break; break;
} }
@@ -130,7 +130,7 @@ public final class PackBits16Decoder implements Decoder {
read += len; read += len;
} }
// Allow -128 for compatibility, see above // Allow -128 for compatibility, see above
else if (mDisableNoop || n != -128) { else if (disableNoop || n != -128) {
// Replicate the next short -n + 1 times // Replicate the next short -n + 1 times
byte value1 = readByte(pStream); byte value1 = readByte(pStream);
byte value2 = readByte(pStream); byte value2 = readByte(pStream);

View File

@@ -63,11 +63,11 @@ import java.io.EOFException;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBitsDecoder.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBitsDecoder.java#1 $
*/ */
public final class PackBitsDecoder implements Decoder { public final class PackBitsDecoder implements Decoder {
private final boolean mDisableNoop; private final boolean disableNoop;
private int mLeftOfRun; private int leftOfRun;
private boolean mSplitRun; private boolean splitRun;
private boolean mEOF; private boolean reachedEOF;
/** Creates a {@code PackBitsDecoder}. */ /** Creates a {@code PackBitsDecoder}. */
public PackBitsDecoder() { public PackBitsDecoder() {
@@ -86,7 +86,7 @@ public final class PackBitsDecoder implements Decoder {
* @param pDisableNoop {@code true} if {@code -128} should be treated as a compressed run, and not a no-op * @param pDisableNoop {@code true} if {@code -128} should be treated as a compressed run, and not a no-op
*/ */
public PackBitsDecoder(final boolean pDisableNoop) { public PackBitsDecoder(final boolean pDisableNoop) {
mDisableNoop = pDisableNoop; disableNoop = pDisableNoop;
} }
/** /**
@@ -100,7 +100,7 @@ public final class PackBitsDecoder implements Decoder {
* @throws IOException * @throws IOException
*/ */
public int decode(final InputStream pStream, final byte[] pBuffer) throws IOException { public int decode(final InputStream pStream, final byte[] pBuffer) throws IOException {
if (mEOF) { if (reachedEOF) {
return -1; return -1;
} }
@@ -111,16 +111,16 @@ public final class PackBitsDecoder implements Decoder {
while (read < max) { while (read < max) {
int n; int n;
if (mSplitRun) { if (splitRun) {
// Continue run // Continue run
n = mLeftOfRun; n = leftOfRun;
mSplitRun = false; splitRun = false;
} }
else { else {
// Start new run // Start new run
int b = pStream.read(); int b = pStream.read();
if (b < 0) { if (b < 0) {
mEOF = true; reachedEOF = true;
break; break;
} }
n = (byte) b; n = (byte) b;
@@ -128,13 +128,13 @@ public final class PackBitsDecoder implements Decoder {
// Split run at or before max // Split run at or before max
if (n >= 0 && n + 1 + read > max) { if (n >= 0 && n + 1 + read > max) {
mLeftOfRun = n; leftOfRun = n;
mSplitRun = true; splitRun = true;
break; break;
} }
else if (n < 0 && -n + 1 + read > max) { else if (n < 0 && -n + 1 + read > max) {
mLeftOfRun = n; leftOfRun = n;
mSplitRun = true; splitRun = true;
break; break;
} }
@@ -146,7 +146,7 @@ public final class PackBitsDecoder implements Decoder {
read += n + 1; read += n + 1;
} }
// Allow -128 for compatibility, see above // Allow -128 for compatibility, see above
else if (mDisableNoop || n != -128) { else if (disableNoop || n != -128) {
// Replicate the next byte -n + 1 times // Replicate the next byte -n + 1 times
byte value = readByte(pStream); byte value = readByte(pStream);

View File

@@ -63,7 +63,7 @@ import java.io.IOException;
*/ */
public final class PackBitsEncoder implements Encoder { public final class PackBitsEncoder implements Encoder {
final private byte[] mBuffer = new byte[128]; final private byte[] buffer = new byte[128];
/** /**
* Creates a {@code PackBitsEncoder}. * Creates a {@code PackBitsEncoder}.
@@ -101,17 +101,17 @@ public final class PackBitsEncoder implements Encoder {
run = 0; run = 0;
while ((run < 128 && ((offset < max && pBuffer[offset] != pBuffer[offset + 1]) while ((run < 128 && ((offset < max && pBuffer[offset] != pBuffer[offset + 1])
|| (offset < maxMinus1 && pBuffer[offset] != pBuffer[offset + 2])))) { || (offset < maxMinus1 && pBuffer[offset] != pBuffer[offset + 2])))) {
mBuffer[run++] = pBuffer[offset++]; buffer[run++] = pBuffer[offset++];
} }
// If last byte, include it in literal run, if space // If last byte, include it in literal run, if space
if (offset == max && run > 0 && run < 128) { if (offset == max && run > 0 && run < 128) {
mBuffer[run++] = pBuffer[offset++]; buffer[run++] = pBuffer[offset++];
} }
if (run > 0) { if (run > 0) {
pStream.write(run - 1); pStream.write(run - 1);
pStream.write(mBuffer, 0, run); pStream.write(buffer, 0, run);
} }
// If last byte, and not space, start new literal run // If last byte, and not space, start new literal run

View File

@@ -49,7 +49,7 @@ final class RLE4Decoder extends AbstractRLEDecoder {
int deltaX = 0; int deltaX = 0;
int deltaY = 0; int deltaY = 0;
while (mSrcY >= 0) { while (srcY >= 0) {
int byte1 = pInput.read(); int byte1 = pInput.read();
int byte2 = checkEOF(pInput.read()); int byte2 = checkEOF(pInput.read());
@@ -58,20 +58,20 @@ final class RLE4Decoder extends AbstractRLEDecoder {
case 0x00: case 0x00:
// End of line // End of line
// NOTE: Some BMPs have double EOLs.. // NOTE: Some BMPs have double EOLs..
if (mSrcX != 0) { if (srcX != 0) {
mSrcX = mRow.length; srcX = row.length;
} }
break; break;
case 0x01: case 0x01:
// End of bitmap // End of bitmap
mSrcX = mRow.length; srcX = row.length;
mSrcY = 0; srcY = 0;
break; break;
case 0x02: case 0x02:
// Delta // Delta
deltaX = mSrcX + pInput.read(); deltaX = srcX + pInput.read();
deltaY = mSrcY - checkEOF(pInput.read()); deltaY = srcY - checkEOF(pInput.read());
mSrcX = mRow.length; srcX = row.length;
break; break;
default: default:
// Absolute mode // Absolute mode
@@ -82,13 +82,13 @@ final class RLE4Decoder extends AbstractRLEDecoder {
boolean paddingByte = (((byte2 + 1) / 2) % 2) != 0; boolean paddingByte = (((byte2 + 1) / 2) % 2) != 0;
while (byte2 > 1) { while (byte2 > 1) {
int packed = checkEOF(pInput.read()); int packed = checkEOF(pInput.read());
mRow[mSrcX++] = (byte) packed; row[srcX++] = (byte) packed;
byte2 -= 2; byte2 -= 2;
} }
if (byte2 == 1) { if (byte2 == 1) {
// TODO: Half byte alignment? Seems to be ok... // TODO: Half byte alignment? Seems to be ok...
int packed = checkEOF(pInput.read()); int packed = checkEOF(pInput.read());
mRow[mSrcX++] = (byte) (packed & 0xf0); row[srcX++] = (byte) (packed & 0xf0);
} }
if (paddingByte) { if (paddingByte) {
checkEOF(pInput.read()); checkEOF(pInput.read());
@@ -100,24 +100,24 @@ final class RLE4Decoder extends AbstractRLEDecoder {
// Encoded mode // Encoded mode
// Replicate the two samples in byte2 as many times as byte1 says // Replicate the two samples in byte2 as many times as byte1 says
while (byte1 > 1) { while (byte1 > 1) {
mRow[mSrcX++] = (byte) byte2; row[srcX++] = (byte) byte2;
byte1 -= 2; byte1 -= 2;
} }
if (byte1 == 1) { if (byte1 == 1) {
// TODO: Half byte alignment? Seems to be ok... // TODO: Half byte alignment? Seems to be ok...
mRow[mSrcX++] = (byte) (byte2 & 0xf0); row[srcX++] = (byte) (byte2 & 0xf0);
} }
} }
// If we're done with a complete row, copy the data // If we're done with a complete row, copy the data
if (mSrcX == mRow.length) { if (srcX == row.length) {
// Move to new position, either absolute (delta) or next line // Move to new position, either absolute (delta) or next line
if (deltaX != 0 || deltaY != 0) { if (deltaX != 0 || deltaY != 0) {
mSrcX = (deltaX + 1) / 2; srcX = (deltaX + 1) / 2;
if (deltaY > mSrcY) { if (deltaY > srcY) {
mSrcY = deltaY; srcY = deltaY;
break; break;
} }
@@ -125,8 +125,8 @@ final class RLE4Decoder extends AbstractRLEDecoder {
deltaY = 0; deltaY = 0;
} }
else { else {
mSrcX = 0; srcX = 0;
mSrcY--; srcY--;
break; break;
} }
} }

View File

@@ -49,7 +49,7 @@ final class RLE8Decoder extends AbstractRLEDecoder {
int deltaX = 0; int deltaX = 0;
int deltaY = 0; int deltaY = 0;
while (mSrcY >= 0) { while (srcY >= 0) {
int byte1 = pInput.read(); int byte1 = pInput.read();
int byte2 = checkEOF(pInput.read()); int byte2 = checkEOF(pInput.read());
@@ -58,27 +58,27 @@ final class RLE8Decoder extends AbstractRLEDecoder {
case 0x00: case 0x00:
// End of line // End of line
// NOTE: Some BMPs have double EOLs.. // NOTE: Some BMPs have double EOLs..
if (mSrcX != 0) { if (srcX != 0) {
mSrcX = mRow.length; srcX = row.length;
} }
break; break;
case 0x01: case 0x01:
// End of bitmap // End of bitmap
mSrcX = mRow.length; srcX = row.length;
mSrcY = 0; srcY = 0;
break; break;
case 0x02: case 0x02:
// Delta // Delta
deltaX = mSrcX + pInput.read(); deltaX = srcX + pInput.read();
deltaY = mSrcY - checkEOF(pInput.read()); deltaY = srcY - checkEOF(pInput.read());
mSrcX = mRow.length; srcX = row.length;
break; break;
default: default:
// Absolute mode // Absolute mode
// Copy the next byte2 (3..255) bytes from file to output // Copy the next byte2 (3..255) bytes from file to output
boolean paddingByte = (byte2 % 2) != 0; boolean paddingByte = (byte2 % 2) != 0;
while (byte2-- > 0) { while (byte2-- > 0) {
mRow[mSrcX++] = (byte) checkEOF(pInput.read()); row[srcX++] = (byte) checkEOF(pInput.read());
} }
if (paddingByte) { if (paddingByte) {
checkEOF(pInput.read()); checkEOF(pInput.read());
@@ -90,26 +90,26 @@ final class RLE8Decoder extends AbstractRLEDecoder {
// Replicate byte2 as many times as byte1 says // Replicate byte2 as many times as byte1 says
byte value = (byte) byte2; byte value = (byte) byte2;
while (byte1-- > 0) { while (byte1-- > 0) {
mRow[mSrcX++] = value; row[srcX++] = value;
} }
} }
// If we're done with a complete row, copy the data // If we're done with a complete row, copy the data
if (mSrcX == mRow.length) { if (srcX == row.length) {
// Move to new position, either absolute (delta) or next line // Move to new position, either absolute (delta) or next line
if (deltaX != 0 || deltaY != 0) { if (deltaX != 0 || deltaY != 0) {
mSrcX = deltaX; srcX = deltaX;
if (deltaY != mSrcY) { if (deltaY != srcY) {
mSrcY = deltaY; srcY = deltaY;
break; break;
} }
deltaX = 0; deltaX = 0;
deltaY = 0; deltaY = 0;
} }
else { else {
mSrcX = 0; srcX = 0;
mSrcY--; srcY--;
break; break;
} }
} }

View File

@@ -60,28 +60,28 @@ public final class CompoundDocument {
}; };
public static final int HEADER_SIZE = 512; public static final int HEADER_SIZE = 512;
private final DataInput mInput; private final DataInput input;
private UUID mUID; private UUID uUID;
private int mSectorSize; private int sectorSize;
private int mShortSectorSize; private int shortSectorSize;
private int mDirectorySId; private int directorySId;
private int mMinStreamSize; private int minStreamSize;
private int mShortSATSID; private int shortSATSId;
private int mShortSATSize; private int shortSATSize;
// Master Sector Allocation Table // Master Sector Allocation Table
private int[] mMasterSAT; private int[] masterSAT;
private int[] mSAT; private int[] SAT;
private int[] mShortSAT; private int[] shortSAT;
private Entry mRootEntry; private Entry rootEntry;
private SIdChain mShortStreamSIdChain; private SIdChain shortStreamSIdChain;
private SIdChain mDirectorySIdChain; private SIdChain directorySIdChain;
private static final int END_OF_CHAIN_SID = -2; private static final int END_OF_CHAIN_SID = -2;
private static final int FREE_SID = -1; private static final int FREE_SID = -1;
@@ -97,7 +97,7 @@ public final class CompoundDocument {
* @throws IOException if an I/O exception occurs while reading the header * @throws IOException if an I/O exception occurs while reading the header
*/ */
public CompoundDocument(final File pFile) throws IOException { public CompoundDocument(final File pFile) throws IOException {
mInput = new LittleEndianRandomAccessFile(FileUtil.resolve(pFile), "r"); input = new LittleEndianRandomAccessFile(FileUtil.resolve(pFile), "r");
// TODO: Might be better to read header on first read operation?! // TODO: Might be better to read header on first read operation?!
// OTOH: It's also good to be fail-fast, so at least we should make // OTOH: It's also good to be fail-fast, so at least we should make
@@ -118,7 +118,7 @@ public final class CompoundDocument {
// For testing only, consider exposing later // For testing only, consider exposing later
CompoundDocument(final SeekableInputStream pInput) throws IOException { CompoundDocument(final SeekableInputStream pInput) throws IOException {
mInput = new SeekableLittleEndianDataInputStream(pInput); input = new SeekableLittleEndianDataInputStream(pInput);
// TODO: Might be better to read header on first read operation?! // TODO: Might be better to read header on first read operation?!
// OTOH: It's also good to be fail-fast, so at least we should make // OTOH: It's also good to be fail-fast, so at least we should make
@@ -134,7 +134,7 @@ public final class CompoundDocument {
* @throws IOException if an I/O exception occurs while reading the header * @throws IOException if an I/O exception occurs while reading the header
*/ */
public CompoundDocument(final ImageInputStream pInput) throws IOException { public CompoundDocument(final ImageInputStream pInput) throws IOException {
mInput = pInput; input = pInput;
// TODO: Might be better to read header on first read operation?! // TODO: Might be better to read header on first read operation?!
// OTOH: It's also good to be fail-fast, so at least we should make // OTOH: It's also good to be fail-fast, so at least we should make
@@ -210,74 +210,76 @@ public final class CompoundDocument {
} }
private void readHeader() throws IOException { private void readHeader() throws IOException {
if (mMasterSAT != null) { if (masterSAT != null) {
return; return;
} }
if (!canRead(mInput, false)) { if (!canRead(input, false)) {
throw new CorruptDocumentException("Not an OLE 2 Compound Document"); throw new CorruptDocumentException("Not an OLE 2 Compound Document");
} }
// UID (seems to be all 0s) // UID (seems to be all 0s)
mUID = new UUID(mInput.readLong(), mInput.readLong()); uUID = new UUID(input.readLong(), input.readLong());
/*int version = */mInput.readUnsignedShort(); /*int version = */
input.readUnsignedShort();
//System.out.println("version: " + version); //System.out.println("version: " + version);
/*int revision = */mInput.readUnsignedShort(); /*int revision = */
input.readUnsignedShort();
//System.out.println("revision: " + revision); //System.out.println("revision: " + revision);
int byteOrder = mInput.readUnsignedShort(); int byteOrder = input.readUnsignedShort();
if (byteOrder != 0xfffe) { if (byteOrder != 0xfffe) {
// Reversed, as I'm allready reading little-endian // Reversed, as I'm allready reading little-endian
throw new CorruptDocumentException("Cannot read big endian OLE 2 Compound Documents"); throw new CorruptDocumentException("Cannot read big endian OLE 2 Compound Documents");
} }
mSectorSize = 1 << mInput.readUnsignedShort(); sectorSize = 1 << input.readUnsignedShort();
//System.out.println("sectorSize: " + mSectorSize + " bytes"); //System.out.println("sectorSize: " + sectorSize + " bytes");
mShortSectorSize = 1 << mInput.readUnsignedShort(); shortSectorSize = 1 << input.readUnsignedShort();
//System.out.println("shortSectorSize: " + mShortSectorSize + " bytes"); //System.out.println("shortSectorSize: " + shortSectorSize + " bytes");
// Reserved // Reserved
if (mInput.skipBytes(10) != 10) { if (input.skipBytes(10) != 10) {
throw new CorruptDocumentException(); throw new CorruptDocumentException();
} }
int SATSize = mInput.readInt(); int SATSize = input.readInt();
//System.out.println("normalSATSize: " + mSATSize); //System.out.println("normalSATSize: " + mSATSize);
mDirectorySId = mInput.readInt(); directorySId = input.readInt();
//System.out.println("directorySId: " + mDirectorySId); //System.out.println("directorySId: " + directorySId);
// Reserved // Reserved
if (mInput.skipBytes(4) != 4) { if (input.skipBytes(4) != 4) {
throw new CorruptDocumentException(); throw new CorruptDocumentException();
} }
mMinStreamSize = mInput.readInt(); minStreamSize = input.readInt();
//System.out.println("minStreamSize: " + mMinStreamSize + " bytes"); //System.out.println("minStreamSize: " + minStreamSize + " bytes");
mShortSATSID = mInput.readInt(); shortSATSId = input.readInt();
//System.out.println("shortSATSID: " + mShortSATSID); //System.out.println("shortSATSId: " + shortSATSId);
mShortSATSize = mInput.readInt(); shortSATSize = input.readInt();
//System.out.println("shortSATSize: " + mShortSATSize); //System.out.println("shortSATSize: " + shortSATSize);
int masterSATSId = mInput.readInt(); int masterSATSId = input.readInt();
//System.out.println("masterSATSId: " + mMasterSATSID); //System.out.println("masterSATSId: " + mMasterSATSID);
int masterSATSize = mInput.readInt(); int masterSATSize = input.readInt();
//System.out.println("masterSATSize: " + mMasterSATSize); //System.out.println("masterSATSize: " + mMasterSATSize);
// Read masterSAT: 436 bytes, containing up to 109 SIDs // Read masterSAT: 436 bytes, containing up to 109 SIDs
//System.out.println("MSAT:"); //System.out.println("MSAT:");
mMasterSAT = new int[SATSize]; masterSAT = new int[SATSize];
final int headerSIds = Math.min(SATSize, 109); final int headerSIds = Math.min(SATSize, 109);
for (int i = 0; i < headerSIds; i++) { for (int i = 0; i < headerSIds; i++) {
mMasterSAT[i] = mInput.readInt(); masterSAT[i] = input.readInt();
//System.out.println("\tSID(" + i + "): " + mMasterSAT[i]); //System.out.println("\tSID(" + i + "): " + masterSAT[i]);
} }
if (masterSATSId == END_OF_CHAIN_SID) { if (masterSATSId == END_OF_CHAIN_SID) {
// End of chain // End of chain
int freeSIdLength = 436 - (SATSize * 4); int freeSIdLength = 436 - (SATSize * 4);
if (mInput.skipBytes(freeSIdLength) != freeSIdLength) { if (input.skipBytes(freeSIdLength) != freeSIdLength) {
throw new CorruptDocumentException(); throw new CorruptDocumentException();
} }
} }
@@ -288,17 +290,17 @@ public final class CompoundDocument {
int index = headerSIds; int index = headerSIds;
for (int i = 0; i < masterSATSize; i++) { for (int i = 0; i < masterSATSize; i++) {
for (int j = 0; j < 127; j++) { for (int j = 0; j < 127; j++) {
int sid = mInput.readInt(); int sid = input.readInt();
switch (sid) { switch (sid) {
case FREE_SID:// Free case FREE_SID:// Free
break; break;
default: default:
mMasterSAT[index++] = sid; masterSAT[index++] = sid;
break; break;
} }
} }
int next = mInput.readInt(); int next = input.readInt();
if (next == END_OF_CHAIN_SID) {// End of chain if (next == END_OF_CHAIN_SID) {// End of chain
break; break;
} }
@@ -309,37 +311,37 @@ public final class CompoundDocument {
} }
private void readSAT() throws IOException { private void readSAT() throws IOException {
if (mSAT != null) { if (SAT != null) {
return; return;
} }
final int intsPerSector = mSectorSize / 4; final int intsPerSector = sectorSize / 4;
// Read the Sector Allocation Table // Read the Sector Allocation Table
mSAT = new int[mMasterSAT.length * intsPerSector]; SAT = new int[masterSAT.length * intsPerSector];
for (int i = 0; i < mMasterSAT.length; i++) { for (int i = 0; i < masterSAT.length; i++) {
seekToSId(mMasterSAT[i], FREE_SID); seekToSId(masterSAT[i], FREE_SID);
for (int j = 0; j < intsPerSector; j++) { for (int j = 0; j < intsPerSector; j++) {
int nextSID = mInput.readInt(); int nextSID = input.readInt();
int index = (j + (i * intsPerSector)); int index = (j + (i * intsPerSector));
mSAT[index] = nextSID; SAT[index] = nextSID;
} }
} }
// Read the short-stream Sector Allocation Table // Read the short-stream Sector Allocation Table
SIdChain chain = getSIdChain(mShortSATSID, FREE_SID); SIdChain chain = getSIdChain(shortSATSId, FREE_SID);
mShortSAT = new int[mShortSATSize * intsPerSector]; shortSAT = new int[shortSATSize * intsPerSector];
for (int i = 0; i < mShortSATSize; i++) { for (int i = 0; i < shortSATSize; i++) {
seekToSId(chain.get(i), FREE_SID); seekToSId(chain.get(i), FREE_SID);
for (int j = 0; j < intsPerSector; j++) { for (int j = 0; j < intsPerSector; j++) {
int nextSID = mInput.readInt(); int nextSID = input.readInt();
int index = (j + (i * intsPerSector)); int index = (j + (i * intsPerSector));
mShortSAT[index] = nextSID; shortSAT[index] = nextSID;
} }
} }
} }
@@ -355,7 +357,7 @@ public final class CompoundDocument {
private SIdChain getSIdChain(final int pSId, final long pStreamSize) throws IOException { private SIdChain getSIdChain(final int pSId, final long pStreamSize) throws IOException {
SIdChain chain = new SIdChain(); SIdChain chain = new SIdChain();
int[] sat = isShortStream(pStreamSize) ? mShortSAT : mSAT; int[] sat = isShortStream(pStreamSize) ? shortSAT : SAT;
int sid = pSId; int sid = pSId;
while (sid != END_OF_CHAIN_SID && sid != FREE_SID) { while (sid != END_OF_CHAIN_SID && sid != FREE_SID) {
@@ -367,7 +369,7 @@ public final class CompoundDocument {
} }
private boolean isShortStream(final long pStreamSize) { private boolean isShortStream(final long pStreamSize) {
return pStreamSize != FREE_SID && pStreamSize < mMinStreamSize; return pStreamSize != FREE_SID && pStreamSize < minStreamSize;
} }
/** /**
@@ -383,56 +385,56 @@ public final class CompoundDocument {
if (isShortStream(pStreamSize)) { if (isShortStream(pStreamSize)) {
// The short-stream is not continouos... // The short-stream is not continouos...
Entry root = getRootEntry(); Entry root = getRootEntry();
if (mShortStreamSIdChain == null) { if (shortStreamSIdChain == null) {
mShortStreamSIdChain = getSIdChain(root.startSId, root.streamSize); shortStreamSIdChain = getSIdChain(root.startSId, root.streamSize);
} }
int shortPerStd = mSectorSize / mShortSectorSize; int shortPerStd = sectorSize / shortSectorSize;
int offset = pSId / shortPerStd; int offset = pSId / shortPerStd;
int shortOffset = pSId - (offset * shortPerStd); int shortOffset = pSId - (offset * shortPerStd);
pos = HEADER_SIZE pos = HEADER_SIZE
+ (mShortStreamSIdChain.get(offset) * (long) mSectorSize) + (shortStreamSIdChain.get(offset) * (long) sectorSize)
+ (shortOffset * (long) mShortSectorSize); + (shortOffset * (long) shortSectorSize);
} }
else { else {
pos = HEADER_SIZE + pSId * (long) mSectorSize; pos = HEADER_SIZE + pSId * (long) sectorSize;
} }
if (mInput instanceof LittleEndianRandomAccessFile) { if (input instanceof LittleEndianRandomAccessFile) {
((LittleEndianRandomAccessFile) mInput).seek(pos); ((LittleEndianRandomAccessFile) input).seek(pos);
} }
else if (mInput instanceof ImageInputStream) { else if (input instanceof ImageInputStream) {
((ImageInputStream) mInput).seek(pos); ((ImageInputStream) input).seek(pos);
} }
else { else {
((SeekableLittleEndianDataInputStream) mInput).seek(pos); ((SeekableLittleEndianDataInputStream) input).seek(pos);
} }
} }
private void seekToDId(final int pDId) throws IOException { private void seekToDId(final int pDId) throws IOException {
if (mDirectorySIdChain == null) { if (directorySIdChain == null) {
mDirectorySIdChain = getSIdChain(mDirectorySId, FREE_SID); directorySIdChain = getSIdChain(directorySId, FREE_SID);
} }
int dIdsPerSId = mSectorSize / Entry.LENGTH; int dIdsPerSId = sectorSize / Entry.LENGTH;
int sIdOffset = pDId / dIdsPerSId; int sIdOffset = pDId / dIdsPerSId;
int dIdOffset = pDId - (sIdOffset * dIdsPerSId); int dIdOffset = pDId - (sIdOffset * dIdsPerSId);
int sId = mDirectorySIdChain.get(sIdOffset); int sId = directorySIdChain.get(sIdOffset);
seekToSId(sId, FREE_SID); seekToSId(sId, FREE_SID);
if (mInput instanceof LittleEndianRandomAccessFile) { if (input instanceof LittleEndianRandomAccessFile) {
LittleEndianRandomAccessFile input = (LittleEndianRandomAccessFile) mInput; LittleEndianRandomAccessFile input = (LittleEndianRandomAccessFile) this.input;
input.seek(input.getFilePointer() + dIdOffset * Entry.LENGTH); input.seek(input.getFilePointer() + dIdOffset * Entry.LENGTH);
} }
else if (mInput instanceof ImageInputStream) { else if (input instanceof ImageInputStream) {
ImageInputStream input = (ImageInputStream) mInput; ImageInputStream input = (ImageInputStream) this.input;
input.seek(input.getStreamPosition() + dIdOffset * Entry.LENGTH); input.seek(input.getStreamPosition() + dIdOffset * Entry.LENGTH);
} }
else { else {
SeekableLittleEndianDataInputStream input = (SeekableLittleEndianDataInputStream) mInput; SeekableLittleEndianDataInputStream input = (SeekableLittleEndianDataInputStream) this.input;
input.seek(input.getStreamPosition() + dIdOffset * Entry.LENGTH); input.seek(input.getStreamPosition() + dIdOffset * Entry.LENGTH);
} }
} }
@@ -442,7 +444,7 @@ public final class CompoundDocument {
// TODO: Detach? Means, we have to copy to a byte buffer, or keep track of // TODO: Detach? Means, we have to copy to a byte buffer, or keep track of
// positions, and seek back and forth (would be cool, but difficult).. // positions, and seek back and forth (would be cool, but difficult)..
int sectorSize = pStreamSize < mMinStreamSize ? mShortSectorSize : mSectorSize; int sectorSize = pStreamSize < minStreamSize ? shortSectorSize : this.sectorSize;
return new Stream(chain, pStreamSize, sectorSize, this); return new Stream(chain, pStreamSize, sectorSize, this);
} }
@@ -453,7 +455,7 @@ public final class CompoundDocument {
byte[] bytes = new byte[Entry.LENGTH]; byte[] bytes = new byte[Entry.LENGTH];
seekToDId(pDirectoryId); seekToDId(pDirectoryId);
mInput.readFully(bytes); input.readFully(bytes);
return new ByteArrayInputStream(bytes); return new ByteArrayInputStream(bytes);
} }
@@ -462,8 +464,8 @@ public final class CompoundDocument {
Entry entry = Entry.readEntry(new LittleEndianDataInputStream( Entry entry = Entry.readEntry(new LittleEndianDataInputStream(
getDirectoryStreamForDId(pDirectoryId) getDirectoryStreamForDId(pDirectoryId)
)); ));
entry.mParent = pParent; entry.parent = pParent;
entry.mDocument = this; entry.document = this;
return entry; return entry;
} }
@@ -527,21 +529,21 @@ public final class CompoundDocument {
} }
public Entry getRootEntry() throws IOException { public Entry getRootEntry() throws IOException {
if (mRootEntry == null) { if (rootEntry == null) {
readSAT(); readSAT();
mRootEntry = getEntry(0, null); rootEntry = getEntry(0, null);
if (mRootEntry.type != Entry.ROOT_STORAGE) { if (rootEntry.type != Entry.ROOT_STORAGE) {
throw new CorruptDocumentException("Invalid root storage type: " + mRootEntry.type); throw new CorruptDocumentException("Invalid root storage type: " + rootEntry.type);
} }
} }
return mRootEntry; return rootEntry;
} }
// @Override // @Override
// public int hashCode() { // public int hashCode() {
// return mUID.hashCode(); // return uUID.hashCode();
// } // }
// //
// @Override // @Override
@@ -555,7 +557,7 @@ public final class CompoundDocument {
// } // }
// //
// if (pOther.getClass() == getClass()) { // if (pOther.getClass() == getClass()) {
// return mUID.equals(((CompoundDocument) pOther).mUID); // return uUID.equals(((CompoundDocument) pOther).uUID);
// } // }
// //
// return false; // return false;
@@ -565,7 +567,7 @@ public final class CompoundDocument {
public String toString() { public String toString() {
return String.format( return String.format(
"%s[uuid: %s, sector size: %d/%d bytes, directory SID: %d, master SAT: %s entries]", "%s[uuid: %s, sector size: %d/%d bytes, directory SID: %d, master SAT: %s entries]",
getClass().getSimpleName(), mUID, mSectorSize, mShortSectorSize, mDirectorySId, mMasterSAT.length getClass().getSimpleName(), uUID, sectorSize, shortSectorSize, directorySId, masterSAT.length
); );
} }
@@ -638,11 +640,11 @@ public final class CompoundDocument {
private boolean fillBuffer() throws IOException { private boolean fillBuffer() throws IOException {
if (mNextSectorPos < mChain.length()) { if (mNextSectorPos < mChain.length()) {
// TODO: Sync on mDocument.mInput here, and we are completely detached... :-) // TODO: Sync on document.input here, and we are completely detached... :-)
// TODO: We also need to sync other places... // TODO: We also need to sync other places...
synchronized (mDocument) { synchronized (mDocument) {
mDocument.seekToSId(mChain.get(mNextSectorPos), mLength); mDocument.seekToSId(mChain.get(mNextSectorPos), mLength);
mDocument.mInput.readFully(mBuffer); mDocument.input.readFully(mBuffer);
} }
mNextSectorPos++; mNextSectorPos++;

View File

@@ -61,9 +61,9 @@ public final class Entry implements Comparable<Entry> {
int startSId; int startSId;
int streamSize; int streamSize;
CompoundDocument mDocument; CompoundDocument document;
Entry mParent; Entry parent;
SortedSet<Entry> mChildren; SortedSet<Entry> children;
public final static int LENGTH = 128; public final static int LENGTH = 128;
@@ -190,7 +190,7 @@ public final class Entry implements Comparable<Entry> {
return null; return null;
} }
return mDocument.getInputStreamForSId(startSId, streamSize); return document.getInputStreamForSId(startSId, streamSize);
} }
/** /**
@@ -248,7 +248,7 @@ public final class Entry implements Comparable<Entry> {
* the root {@code Entry} * the root {@code Entry}
*/ */
public Entry getParentEntry() { public Entry getParentEntry() {
return mParent; return parent;
} }
/** /**
@@ -266,7 +266,7 @@ public final class Entry implements Comparable<Entry> {
Entry dummy = new Entry(); Entry dummy = new Entry();
dummy.name = pName; dummy.name = pName;
dummy.mParent = this; dummy.parent = this;
SortedSet child = getChildEntries().tailSet(dummy); SortedSet child = getChildEntries().tailSet(dummy);
return (Entry) child.first(); return (Entry) child.first();
@@ -279,26 +279,26 @@ public final class Entry implements Comparable<Entry> {
* @throws java.io.IOException if an I/O exception occurs * @throws java.io.IOException if an I/O exception occurs
*/ */
public SortedSet<Entry> getChildEntries() throws IOException { public SortedSet<Entry> getChildEntries() throws IOException {
if (mChildren == null) { if (children == null) {
if (isFile() || rootNodeDId == -1) { if (isFile() || rootNodeDId == -1) {
mChildren = NO_CHILDREN; children = NO_CHILDREN;
} }
else { else {
// Start at root node in R/B tree, and raed to the left and right, // Start at root node in R/B tree, and raed to the left and right,
// re-build tree, according to the docs // re-build tree, according to the docs
mChildren = mDocument.getEntries(rootNodeDId, this); children = document.getEntries(rootNodeDId, this);
} }
} }
return mChildren; return children;
} }
@Override @Override
public String toString() { public String toString() {
return "\"" + name + "\"" return "\"" + name + "\""
+ " (" + (isFile() ? "Document" : (isDirectory() ? "Directory" : "Root")) + " (" + (isFile() ? "Document" : (isDirectory() ? "Directory" : "Root"))
+ (mParent != null ? ", parent: \"" + mParent.getName() + "\"" : "") + (parent != null ? ", parent: \"" + parent.getName() + "\"" : "")
+ (isFile() ? "" : ", children: " + (mChildren != null ? String.valueOf(mChildren.size()) : "(unknown)")) + (isFile() ? "" : ", children: " + (children != null ? String.valueOf(children.size()) : "(unknown)"))
+ ", SId=" + startSId + ", length=" + streamSize + ")"; + ", SId=" + startSId + ", length=" + streamSize + ")";
} }
@@ -312,8 +312,8 @@ public final class Entry implements Comparable<Entry> {
} }
Entry other = (Entry) pOther; Entry other = (Entry) pOther;
return name.equals(other.name) && (mParent == other.mParent return name.equals(other.name) && (parent == other.parent
|| (mParent != null && mParent.equals(other.mParent))); || (parent != null && parent.equals(other.parent)));
} }
@Override @Override

View File

@@ -37,11 +37,10 @@ import java.net.*;
* @see SimpleAuthenticator * @see SimpleAuthenticator
* @see java.net.Authenticator * @see java.net.Authenticator
* *
* @author Harald Kuhr (haraldk@iconmedialab.no), * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version 1.0 * @version 1.0
*/ */
public interface AuthenticatorFilter { public interface AuthenticatorFilter {
public boolean accept(InetAddress pAddress, int pPort, String pProtocol, public boolean accept(InetAddress pAddress, int pPort, String pProtocol, String pPrompt, String pScheme);
String pPrompt, String pScheme);
} }

View File

@@ -26,7 +26,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package com.twelvemonkeys.util; package com.twelvemonkeys.net;
import com.twelvemonkeys.io.*; import com.twelvemonkeys.io.*;
import com.twelvemonkeys.io.enc.Base64Decoder; import com.twelvemonkeys.io.enc.Base64Decoder;
@@ -41,8 +41,9 @@ import java.io.*;
* @author unascribed * @author unascribed
* @author last modified by $Author: haku $ * @author last modified by $Author: haku $
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/BASE64.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/BASE64.java#1 $
* @deprecated Use {@link com.twelvemonkeys.io.enc.Base64Encoder}/{@link Base64Decoder} instead
*/ */
public class BASE64 { class BASE64 {
/** /**
* This array maps the characters to their 6 bit values * This array maps the characters to their 6 bit values

View File

@@ -29,7 +29,6 @@
package com.twelvemonkeys.net; package com.twelvemonkeys.net;
import com.twelvemonkeys.lang.StringUtil; import com.twelvemonkeys.lang.StringUtil;
import com.twelvemonkeys.util.BASE64;
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
@@ -65,18 +64,18 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
private final static String HTTP_HEADER_END = "\r\n\r\n"; private final static String HTTP_HEADER_END = "\r\n\r\n";
private static final String HEADER_WWW_AUTH = "WWW-Authenticate"; private static final String HEADER_WWW_AUTH = "WWW-Authenticate";
private final static int BUF_SIZE = 8192; private final static int BUF_SIZE = 8192;
private int mMaxRedirects = (System.getProperty("http.maxRedirects") != null) private int maxRedirects = (System.getProperty("http.maxRedirects") != null)
? Integer.parseInt(System.getProperty("http.maxRedirects")) ? Integer.parseInt(System.getProperty("http.maxRedirects"))
: 20; : 20;
protected int mTimeout = -1; protected int timeout = -1;
protected int mConnectTimeout = -1; protected int connectTimeout = -1;
private Socket mSocket = null; private Socket socket = null;
protected InputStream mErrorStream = null; protected InputStream errorStream = null;
protected InputStream mInputStream = null; protected InputStream inputStream = null;
protected OutputStream mOutputStream = null; protected OutputStream outputStream = null;
private String[] mResponseHeaders = null; private String[] responseHeaders = null;
protected Properties mResponseHeaderFields = null; protected Properties responseHeaderFields = null;
protected Properties mRequestProperties = new Properties(); protected Properties requestProperties = new Properties();
/** /**
* Creates a HttpURLConnection. * Creates a HttpURLConnection.
@@ -114,7 +113,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
protected HttpURLConnection(URL pURL, int pTimeout, int pConnectTimeout) { protected HttpURLConnection(URL pURL, int pTimeout, int pConnectTimeout) {
super(pURL); super(pURL);
setTimeout(pTimeout); setTimeout(pTimeout);
mConnectTimeout = pConnectTimeout; connectTimeout = pConnectTimeout;
} }
/** /**
@@ -135,13 +134,13 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
if (connected) { if (connected) {
throw new IllegalAccessError("Already connected"); throw new IllegalAccessError("Already connected");
} }
String oldValue = mRequestProperties.getProperty(pKey); String oldValue = requestProperties.getProperty(pKey);
if (oldValue == null) { if (oldValue == null) {
mRequestProperties.setProperty(pKey, pValue); requestProperties.setProperty(pKey, pValue);
} }
else { else {
mRequestProperties.setProperty(pKey, oldValue + ", " + pValue); requestProperties.setProperty(pKey, oldValue + ", " + pValue);
} }
} }
@@ -158,7 +157,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
if (connected) { if (connected) {
throw new IllegalAccessError("Already connected"); throw new IllegalAccessError("Already connected");
} }
return mRequestProperties.getProperty(pKey); return requestProperties.getProperty(pKey);
} }
/** /**
@@ -212,7 +211,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
* if there is no such field in the header. * if there is no such field in the header.
*/ */
public String getHeaderField(String pName) { public String getHeaderField(String pName) {
return mResponseHeaderFields.getProperty(StringUtil.toLowerCase(pName)); return responseHeaderFields.getProperty(StringUtil.toLowerCase(pName));
} }
/** /**
@@ -230,10 +229,10 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
*/ */
public String getHeaderField(int pIndex) { public String getHeaderField(int pIndex) {
// TODO: getInputStream() first, to make sure we have header fields // TODO: getInputStream() first, to make sure we have header fields
if (pIndex >= mResponseHeaders.length) { if (pIndex >= responseHeaders.length) {
return null; return null;
} }
String field = mResponseHeaders[pIndex]; String field = responseHeaders[pIndex];
// pIndex == 0, means the response code etc (i.e. "HTTP/1.1 200 OK"). // pIndex == 0, means the response code etc (i.e. "HTTP/1.1 200 OK").
if ((pIndex == 0) || (field == null)) { if ((pIndex == 0) || (field == null)) {
@@ -256,10 +255,10 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
*/ */
public String getHeaderFieldKey(int pIndex) { public String getHeaderFieldKey(int pIndex) {
// TODO: getInputStream() first, to make sure we have header fields // TODO: getInputStream() first, to make sure we have header fields
if (pIndex >= mResponseHeaders.length) { if (pIndex >= responseHeaders.length) {
return null; return null;
} }
String field = mResponseHeaders[pIndex]; String field = responseHeaders[pIndex];
if (StringUtil.isEmpty(field)) { if (StringUtil.isEmpty(field)) {
return null; return null;
@@ -283,10 +282,10 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
if (pTimeout < 0) { // Must be positive if (pTimeout < 0) { // Must be positive
throw new IllegalArgumentException("Timeout must be positive."); throw new IllegalArgumentException("Timeout must be positive.");
} }
mTimeout = pTimeout; timeout = pTimeout;
if (mSocket != null) { if (socket != null) {
try { try {
mSocket.setSoTimeout(pTimeout); socket.setSoTimeout(pTimeout);
} }
catch (SocketException se) { catch (SocketException se) {
// Not much to do about that... // Not much to do about that...
@@ -305,12 +304,12 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
public int getTimeout() { public int getTimeout() {
try { try {
return ((mSocket != null) return ((socket != null)
? mSocket.getSoTimeout() ? socket.getSoTimeout()
: mTimeout); : timeout);
} }
catch (SocketException se) { catch (SocketException se) {
return mTimeout; return timeout;
} }
} }
@@ -332,24 +331,24 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
} }
int length; int length;
if (mInputStream == null) { if (inputStream == null) {
return null; return null;
} }
// "De-chunk" the output stream // "De-chunk" the output stream
else if ("chunked".equalsIgnoreCase(getHeaderField("Transfer-Encoding"))) { else if ("chunked".equalsIgnoreCase(getHeaderField("Transfer-Encoding"))) {
if (!(mInputStream instanceof ChunkedInputStream)) { if (!(inputStream instanceof ChunkedInputStream)) {
mInputStream = new ChunkedInputStream(mInputStream); inputStream = new ChunkedInputStream(inputStream);
} }
} }
// Make sure we don't wait forever, if the content-length is known // Make sure we don't wait forever, if the content-length is known
else if ((length = getHeaderFieldInt("Content-Length", -1)) >= 0) { else if ((length = getHeaderFieldInt("Content-Length", -1)) >= 0) {
if (!(mInputStream instanceof FixedLengthInputStream)) { if (!(inputStream instanceof FixedLengthInputStream)) {
mInputStream = new FixedLengthInputStream(mInputStream, length); inputStream = new FixedLengthInputStream(inputStream, length);
} }
} }
return mInputStream; return inputStream;
} }
/** /**
@@ -364,7 +363,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
if (!connected) { if (!connected) {
connect(); connect();
} }
return mOutputStream; return outputStream;
} }
/** /**
@@ -374,15 +373,15 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
* instance can be reused for other requests. * instance can be reused for other requests.
*/ */
public void disconnect() { public void disconnect() {
if (mSocket != null) { if (socket != null) {
try { try {
mSocket.close(); socket.close();
} }
catch (IOException ioe) { catch (IOException ioe) {
// Does not matter, I guess. // Does not matter, I guess.
} }
mSocket = null; socket = null;
} }
connected = false; connected = false;
} }
@@ -397,37 +396,37 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
: HTTP_DEFAULT_PORT; : HTTP_DEFAULT_PORT;
// Create socket if we don't have one // Create socket if we don't have one
if (mSocket == null) { if (socket == null) {
//mSocket = new Socket(pURL.getHost(), port); // Blocks... //socket = new Socket(pURL.getHost(), port); // Blocks...
mSocket = createSocket(pURL, port, mConnectTimeout); socket = createSocket(pURL, port, connectTimeout);
mSocket.setSoTimeout(mTimeout); socket.setSoTimeout(timeout);
} }
// Get Socket output stream // Get Socket output stream
OutputStream os = mSocket.getOutputStream(); OutputStream os = socket.getOutputStream();
// Connect using HTTP // Connect using HTTP
writeRequestHeaders(os, pURL, method, mRequestProperties, usingProxy(), pAuth, pAuthType); writeRequestHeaders(os, pURL, method, requestProperties, usingProxy(), pAuth, pAuthType);
// Get response input stream // Get response input stream
InputStream sis = mSocket.getInputStream(); InputStream sis = socket.getInputStream();
BufferedInputStream is = new BufferedInputStream(sis); BufferedInputStream is = new BufferedInputStream(sis);
// Detatch reponse headers from reponse input stream // Detatch reponse headers from reponse input stream
InputStream header = detatchResponseHeader(is); InputStream header = detatchResponseHeader(is);
// Parse headers and set response code/message // Parse headers and set response code/message
mResponseHeaders = parseResponseHeader(header); responseHeaders = parseResponseHeader(header);
mResponseHeaderFields = parseHeaderFields(mResponseHeaders); responseHeaderFields = parseHeaderFields(responseHeaders);
//System.err.println("Headers fields:"); //System.err.println("Headers fields:");
//mResponseHeaderFields.list(System.err); //responseHeaderFields.list(System.err);
// Test HTTP response code, to see if further action is needed // Test HTTP response code, to see if further action is needed
switch (getResponseCode()) { switch (getResponseCode()) {
case HTTP_OK: case HTTP_OK:
// 200 OK // 200 OK
mInputStream = is; inputStream = is;
mErrorStream = null; errorStream = null;
break; break;
/* /*
@@ -472,7 +471,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
// Avoid infinite loop // Avoid infinite loop
if (pRetries++ <= 0) { if (pRetries++ <= 0) {
throw new ProtocolException("Server redirected too many times (" + mMaxRedirects + ") (Authentication required: " + auth + ")"); // This is what sun.net.www.protocol.http.HttpURLConnection does throw new ProtocolException("Server redirected too many times (" + maxRedirects + ") (Authentication required: " + auth + ")"); // This is what sun.net.www.protocol.http.HttpURLConnection does
} }
else if (pa != null) { else if (pa != null) {
connect(pURL, pa, method, pRetries); connect(pURL, pa, method, pRetries);
@@ -506,8 +505,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
// Test if we can reuse the Socket // Test if we can reuse the Socket
if (!(newLoc.getAuthority().equals(pURL.getAuthority()) && (newLoc.getPort() == pURL.getPort()))) { if (!(newLoc.getAuthority().equals(pURL.getAuthority()) && (newLoc.getPort() == pURL.getPort()))) {
mSocket.close(); // Close the socket, won't need it anymore socket.close(); // Close the socket, won't need it anymore
mSocket = null; socket = null;
} }
if (location != null) { if (location != null) {
//System.err.println("Redirecting to " + location); //System.err.println("Redirecting to " + location);
@@ -526,22 +525,22 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
default : default :
// Not 200 OK, or any of the redirect responses // Not 200 OK, or any of the redirect responses
// Probably an error... // Probably an error...
mErrorStream = is; errorStream = is;
mInputStream = null; inputStream = null;
} }
// --- Need rethinking... // --- Need rethinking...
// No further questions, let the Socket wait forever (until the server // No further questions, let the Socket wait forever (until the server
// closes the connection) // closes the connection)
//mSocket.setSoTimeout(0); //socket.setSoTimeout(0);
// Probably not... The timeout should only kick if the read BLOCKS. // Probably not... The timeout should only kick if the read BLOCKS.
// Shutdown output, meaning any writes to the outputstream below will // Shutdown output, meaning any writes to the outputstream below will
// probably fail... // probably fail...
//mSocket.shutdownOutput(); //socket.shutdownOutput();
// Not a good idea at all... POSTs need the outputstream to send the // Not a good idea at all... POSTs need the outputstream to send the
// form-data. // form-data.
// --- /Need rethinking. // --- /Need rethinking.
mOutputStream = os; outputStream = os;
} }
private static interface SocketConnector extends Runnable { private static interface SocketConnector extends Runnable {
@@ -663,7 +662,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
return; // Ignore return; // Ignore
} }
connected = true; connected = true;
connect(url, null, null, mMaxRedirects); connect(url, null, null, maxRedirects);
} }
/** /**

View File

@@ -3,7 +3,6 @@ package com.twelvemonkeys.net;
import com.twelvemonkeys.io.FileUtil; import com.twelvemonkeys.io.FileUtil;
import com.twelvemonkeys.lang.StringUtil; import com.twelvemonkeys.lang.StringUtil;
import com.twelvemonkeys.lang.DateUtil; import com.twelvemonkeys.lang.DateUtil;
import com.twelvemonkeys.util.BASE64;
import com.twelvemonkeys.util.CollectionUtil; import com.twelvemonkeys.util.CollectionUtil;
import java.io.*; import java.io.*;

View File

@@ -28,29 +28,31 @@
package com.twelvemonkeys.net; package com.twelvemonkeys.net;
import com.twelvemonkeys.lang.Validate;
import java.net.Authenticator; import java.net.Authenticator;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.PasswordAuthentication; import java.net.PasswordAuthentication;
import java.net.URL; import java.net.URL;
import java.util.Hashtable; import java.util.HashMap;
import java.util.Map;
/** /**
* A simple Authenticator implementation. * A simple Authenticator implementation.
* Singleton class, obtain reference through the static * Singleton class, obtain reference through the static
* {@code getInstance} method. * {@code getInstance} method.
* <P> * <p/>
* <EM>After swearing, sweating, pulling my hair, banging my head repeatedly * <EM>After swearing, sweating, pulling my hair, banging my head repeatedly
* into the walls and reading the java.net.Authenticator API documentation * into the walls and reading the java.net.Authenticator API documentation
* once more, an idea came to my mind. This is the result. I hope you find it * once more, an idea came to my mind. This is the result. I hope you find it
* useful. -- Harald K.</EM> * useful. -- Harald K.</EM>
* *
* @see java.net.Authenticator
*
* @author Harald Kuhr (haraldk@iconmedialab.no) * @author Harald Kuhr (haraldk@iconmedialab.no)
* @version 1.0 * @version 1.0
* @see java.net.Authenticator
*/ */
public class SimpleAuthenticator extends Authenticator { public class SimpleAuthenticator extends Authenticator {
/** The reference to the single instance of this class. */ /** The reference to the single instance of this class. */
private static SimpleAuthenticator sInstance = null; private static SimpleAuthenticator sInstance = null;
/** Keeps track of the state of this class. */ /** Keeps track of the state of this class. */
@@ -63,237 +65,179 @@ public class SimpleAuthenticator extends Authenticator {
/** Basic authentication scheme. */ /** Basic authentication scheme. */
public final static String BASIC = "Basic"; public final static String BASIC = "Basic";
/** /** The hastable that keeps track of the PasswordAuthentications. */
* The hastable that keeps track of the PasswordAuthentications. protected Map<AuthKey, PasswordAuthentication> passwordAuthentications = null;
*/
protected Hashtable mPasswordAuthentications = null; /** The hastable that keeps track of the Authenticators. */
protected Map<PasswordAuthenticator, AuthenticatorFilter> authenticators = null;
/**
* The hastable that keeps track of the Authenticators.
*/
protected Hashtable mAuthenticators = null;
/**
* Creates a SimpleAuthenticator.
*/
/** Creates a SimpleAuthenticator. */
private SimpleAuthenticator() { private SimpleAuthenticator() {
mPasswordAuthentications = new Hashtable(); passwordAuthentications = new HashMap<AuthKey, PasswordAuthentication>();
mAuthenticators = new Hashtable(); authenticators = new HashMap<PasswordAuthenticator, AuthenticatorFilter>();
} }
/** /**
* Gets the SimpleAuthenticator instance and registers it through the * Gets the SimpleAuthenticator instance and registers it through the
* Authenticator.setDefault(). If there is no current instance * Authenticator.setDefault(). If there is no current instance
* of the SimpleAuthenticator in the VM, one is created. This method will * of the SimpleAuthenticator in the VM, one is created. This method will
* try to figure out if the setDefault() succeeded (a hack), and will * try to figure out if the setDefault() succeeded (a hack), and will
* return null if it was not able to register the instance as default. * return null if it was not able to register the instance as default.
* *
* @return The single instance of this class, or null, if another * @return The single instance of this class, or null, if another
* Authenticator is allready registered as default. * Authenticator is allready registered as default.
*/ */
public static synchronized SimpleAuthenticator getInstance() { public static synchronized SimpleAuthenticator getInstance() {
if (!sInitialized) { if (!sInitialized) {
// Create an instance // Create an instance
sInstance = new SimpleAuthenticator(); sInstance = new SimpleAuthenticator();
// Try to set default (this may quietly fail...) // Try to set default (this may quietly fail...)
Authenticator.setDefault(sInstance); Authenticator.setDefault(sInstance);
// A hack to figure out if we really did set the authenticator // A hack to figure out if we really did set the authenticator
PasswordAuthentication pa = PasswordAuthentication pa = Authenticator.requestPasswordAuthentication(null, FOURTYTWO, null, null, MAGIC);
Authenticator.requestPasswordAuthentication(null, FOURTYTWO,
null, null, MAGIC);
// If this test returns false, we didn't succeed, so we set the // If this test returns false, we didn't succeed, so we set the
// instance back to null. // instance back to null.
if (pa == null || !MAGIC.equals(pa.getUserName()) || if (pa == null || !MAGIC.equals(pa.getUserName()) || !("" + FOURTYTWO).equals(new String(pa.getPassword()))) {
!("" + FOURTYTWO).equals(new String(pa.getPassword()))) sInstance = null;
sInstance = null; }
// Done // Done
sInitialized = true; sInitialized = true;
} }
return sInstance; return sInstance;
} }
/** /**
* Gets the PasswordAuthentication for the request. Called when password * Gets the PasswordAuthentication for the request. Called when password
* authorization is needed. * authorization is needed.
* *
* @return The PasswordAuthentication collected from the user, or null if * @return The PasswordAuthentication collected from the user, or null if
* none is provided. * none is provided.
*/ */
protected PasswordAuthentication getPasswordAuthentication() { protected PasswordAuthentication getPasswordAuthentication() {
// Don't worry, this is just a hack to figure out if we were able // Don't worry, this is just a hack to figure out if we were able
// to set this Authenticator through the setDefault method. // to set this Authenticator through the setDefault method.
if (!sInitialized && MAGIC.equals(getRequestingScheme()) if (!sInitialized && MAGIC.equals(getRequestingScheme()) && getRequestingPort() == FOURTYTWO) {
&& getRequestingPort() == FOURTYTWO) return new PasswordAuthentication(MAGIC, ("" + FOURTYTWO).toCharArray());
return new PasswordAuthentication(MAGIC, ("" + FOURTYTWO) }
.toCharArray()); /*
/* System.err.println("getPasswordAuthentication");
System.err.println("getPasswordAuthentication"); System.err.println(getRequestingSite());
System.err.println(getRequestingSite()); System.err.println(getRequestingPort());
System.err.println(getRequestingPort()); System.err.println(getRequestingProtocol());
System.err.println(getRequestingProtocol()); System.err.println(getRequestingPrompt());
System.err.println(getRequestingPrompt()); System.err.println(getRequestingScheme());
System.err.println(getRequestingScheme()); */
*/
// TODO: // TODO:
// Look for a more specific PasswordAuthenticatior before using // Look for a more specific PasswordAuthenticatior before using
// Default: // Default:
// //
// if (...) // if (...)
// return pa.requestPasswordAuthentication(getRequestingSite(), // return pa.requestPasswordAuthentication(getRequestingSite(),
// getRequestingPort(), // getRequestingPort(),
// getRequestingProtocol(), // getRequestingProtocol(),
// getRequestingPrompt(), // getRequestingPrompt(),
// getRequestingScheme()); // getRequestingScheme());
return (PasswordAuthentication) return passwordAuthentications.get(new AuthKey(getRequestingSite(),
mPasswordAuthentications.get(new AuthKey(getRequestingSite(), getRequestingPort(),
getRequestingPort(), getRequestingProtocol(),
getRequestingProtocol(), getRequestingPrompt(),
getRequestingPrompt(), getRequestingScheme()));
getRequestingScheme()));
} }
/** /** Registers a PasswordAuthentication with a given URL address. */
* Registers a PasswordAuthentication with a given URL address. public PasswordAuthentication registerPasswordAuthentication(URL pURL, PasswordAuthentication pPA) {
* return registerPasswordAuthentication(NetUtil.createInetAddressFromURL(pURL),
*/ pURL.getPort(),
pURL.getProtocol(),
public PasswordAuthentication registerPasswordAuthentication(URL pURL, null, // Prompt/Realm
PasswordAuthentication pPA) { BASIC,
return registerPasswordAuthentication(NetUtil.createInetAddressFromURL(pURL), pPA);
pURL.getPort(),
pURL.getProtocol(),
null, // Prompt/Realm
BASIC,
pPA);
} }
/** /** Registers a PasswordAuthentication with a given net address. */
* Registers a PasswordAuthentication with a given net address. public PasswordAuthentication registerPasswordAuthentication(InetAddress pAddress, int pPort, String pProtocol, String pPrompt, String pScheme, PasswordAuthentication pPA) {
* /*
*/ System.err.println("registerPasswordAuthentication");
System.err.println(pAddress);
System.err.println(pPort);
System.err.println(pProtocol);
System.err.println(pPrompt);
System.err.println(pScheme);
*/
public PasswordAuthentication registerPasswordAuthentication( return passwordAuthentications.put(new AuthKey(pAddress, pPort, pProtocol, pPrompt, pScheme), pPA);
InetAddress pAddress, int pPort, String pProtocol,
String pPrompt, String pScheme, PasswordAuthentication pPA)
{
/*
System.err.println("registerPasswordAuthentication");
System.err.println(pAddress);
System.err.println(pPort);
System.err.println(pProtocol);
System.err.println(pPrompt);
System.err.println(pScheme);
*/
return (PasswordAuthentication)
mPasswordAuthentications.put(new AuthKey(pAddress, pPort,
pProtocol, pPrompt,
pScheme),
pPA);
} }
/** /** Unregisters a PasswordAuthentication with a given URL address. */
* Unregisters a PasswordAuthentication with a given URL address.
*
*/
public PasswordAuthentication unregisterPasswordAuthentication(URL pURL) { public PasswordAuthentication unregisterPasswordAuthentication(URL pURL) {
return unregisterPasswordAuthentication(NetUtil.createInetAddressFromURL(pURL), return unregisterPasswordAuthentication(NetUtil.createInetAddressFromURL(pURL), pURL.getPort(), pURL.getProtocol(), null, BASIC);
pURL.getPort(),
pURL.getProtocol(),
null,
BASIC);
} }
/** /** Unregisters a PasswordAuthentication with a given net address. */
* Unregisters a PasswordAuthentication with a given net address. public PasswordAuthentication unregisterPasswordAuthentication(InetAddress pAddress, int pPort, String pProtocol, String pPrompt, String pScheme) {
* return passwordAuthentications.remove(new AuthKey(pAddress, pPort, pProtocol, pPrompt, pScheme));
*/
public PasswordAuthentication unregisterPasswordAuthentication(
InetAddress pAddress, int pPort, String pProtocol,
String pPrompt, String pScheme)
{
return (PasswordAuthentication)
mPasswordAuthentications.remove(new AuthKey(pAddress, pPort,
pProtocol, pPrompt,
pScheme));
} }
/** /**
* TODO: Registers a PasswordAuthenticator that can answer authentication * TODO: Registers a PasswordAuthenticator that can answer authentication
* requests. * requests.
* *
* @see PasswordAuthenticator * @see PasswordAuthenticator
*/ */
public void registerPasswordAuthenticator(PasswordAuthenticator pPA, AuthenticatorFilter pFilter) {
public void registerPasswordAuthenticator(PasswordAuthenticator pPA, authenticators.put(pPA, pFilter);
AuthenticatorFilter pFilter) {
mAuthenticators.put(pPA, pFilter);
} }
/** /**
* TODO: Unregisters a PasswordAuthenticator that can answer authentication * TODO: Unregisters a PasswordAuthenticator that can answer authentication
* requests. * requests.
* *
* @see PasswordAuthenticator * @see PasswordAuthenticator
*/ */
public void unregisterPasswordAuthenticator(PasswordAuthenticator pPA) { public void unregisterPasswordAuthenticator(PasswordAuthenticator pPA) {
mAuthenticators.remove(pPA); authenticators.remove(pPA);
} }
} }
/** /**
* Utility class, used for caching the PasswordAuthentication objects. * Utility class, used for caching the PasswordAuthentication objects.
* Everything but address may be null * Everything but address may be null
*/ */
class AuthKey { class AuthKey {
InetAddress mAddress = null;
int mPort = -1;
String mProtocol = null;
String mPrompt = null;
String mScheme = null;
AuthKey(InetAddress pAddress, int pPort, String pProtocol, InetAddress address = null;
String pPrompt, String pScheme) { int port = -1;
if (pAddress == null) String protocol = null;
throw new IllegalArgumentException("Address argument can't be null!"); String prompt = null;
String scheme = null;
mAddress = pAddress; AuthKey(InetAddress pAddress, int pPort, String pProtocol, String pPrompt, String pScheme) {
mPort = pPort; Validate.notNull(pAddress, "address");
mProtocol = pProtocol;
mPrompt = pPrompt;
mScheme = pScheme;
// System.out.println("Created: " + this); address = pAddress;
port = pPort;
protocol = pProtocol;
prompt = pPrompt;
scheme = pScheme;
// System.out.println("Created: " + this);
} }
/** /** Creates a string representation of this object. */
* Creates a string representation of this object.
*/
public String toString() { public String toString() {
return "AuthKey[" + mAddress + ":" + mPort + "/" + mProtocol + " \"" + mPrompt + "\" (" + mScheme + ")]"; return "AuthKey[" + address + ":" + port + "/" + protocol + " \"" + prompt + "\" (" + scheme + ")]";
} }
public boolean equals(Object pObj) { public boolean equals(Object pObj) {
return (pObj instanceof AuthKey ? equals((AuthKey) pObj) : false); return (pObj instanceof AuthKey && equals((AuthKey) pObj));
} }
// Ahem.. Breaks the rule from Object.equals(Object): // Ahem.. Breaks the rule from Object.equals(Object):
@@ -302,25 +246,25 @@ class AuthKey {
// should return true. // should return true.
public boolean equals(AuthKey pKey) { public boolean equals(AuthKey pKey) {
// Maybe allow nulls, and still be equal? // Maybe allow nulls, and still be equal?
return (mAddress.equals(pKey.mAddress) return (address.equals(pKey.address)
&& (mPort == -1 && (port == -1
|| pKey.mPort == -1 || pKey.port == -1
|| mPort == pKey.mPort) || port == pKey.port)
&& (mProtocol == null && (protocol == null
|| pKey.mProtocol == null || pKey.protocol == null
|| mProtocol.equals(pKey.mProtocol)) || protocol.equals(pKey.protocol))
&& (mPrompt == null && (prompt == null
|| pKey.mPrompt == null || pKey.prompt == null
|| mPrompt.equals(pKey.mPrompt)) || prompt.equals(pKey.prompt))
&& (mScheme == null && (scheme == null
|| pKey.mScheme == null || pKey.scheme == null
|| mScheme.equalsIgnoreCase(pKey.mScheme))); || scheme.equalsIgnoreCase(pKey.scheme)));
} }
public int hashCode() { public int hashCode() {
// There won't be too many pr address, will it? ;-) // There won't be too many pr address, will it? ;-)
return mAddress.hashCode(); return address.hashCode();
} }
} }

View File

@@ -52,13 +52,13 @@ public final class DOMSerializer {
private static final String PARAM_PRETTY_PRINT = "format-pretty-print"; private static final String PARAM_PRETTY_PRINT = "format-pretty-print";
private static final String PARAM_XML_DECLARATION = "xml-declaration"; private static final String PARAM_XML_DECLARATION = "xml-declaration";
private final LSSerializer mSerializer; private final LSSerializer serializer;
private final LSOutput mOutput; private final LSOutput output;
private DOMSerializer() { private DOMSerializer() {
DOMImplementationLS domImpl = Support.getImplementation(); DOMImplementationLS domImpl = Support.getImplementation();
mSerializer = domImpl.createLSSerializer(); serializer = domImpl.createLSSerializer();
mOutput = domImpl.createLSOutput(); output = domImpl.createLSOutput();
} }
/** /**
@@ -71,8 +71,8 @@ public final class DOMSerializer {
public DOMSerializer(final OutputStream pStream, final String pEncoding) { public DOMSerializer(final OutputStream pStream, final String pEncoding) {
this(); this();
mOutput.setByteStream(pStream); output.setByteStream(pStream);
mOutput.setEncoding(pEncoding); output.setEncoding(pEncoding);
} }
/** /**
@@ -84,17 +84,17 @@ public final class DOMSerializer {
public DOMSerializer(final Writer pStream) { public DOMSerializer(final Writer pStream) {
this(); this();
mOutput.setCharacterStream(pStream); output.setCharacterStream(pStream);
} }
/* /*
// TODO: Is it useful? // TODO: Is it useful?
public void setNewLine(final String pNewLine) { public void setNewLine(final String pNewLine) {
mSerializer.setNewLine(pNewLine); serializer.setNewLine(pNewLine);
} }
public String getNewLine() { public String getNewLine() {
return mSerializer.getNewLine(); return serializer.getNewLine();
} }
*/ */
@@ -107,18 +107,18 @@ public final class DOMSerializer {
* @param pPrettyPrint {@code true} to enable pretty printing * @param pPrettyPrint {@code true} to enable pretty printing
*/ */
public void setPrettyPrint(final boolean pPrettyPrint) { public void setPrettyPrint(final boolean pPrettyPrint) {
DOMConfiguration configuration = mSerializer.getDomConfig(); DOMConfiguration configuration = serializer.getDomConfig();
if (configuration.canSetParameter(PARAM_PRETTY_PRINT, pPrettyPrint)) { if (configuration.canSetParameter(PARAM_PRETTY_PRINT, pPrettyPrint)) {
configuration.setParameter(PARAM_PRETTY_PRINT, pPrettyPrint); configuration.setParameter(PARAM_PRETTY_PRINT, pPrettyPrint);
} }
} }
public boolean getPrettyPrint() { public boolean getPrettyPrint() {
return Boolean.TRUE.equals(mSerializer.getDomConfig().getParameter(PARAM_PRETTY_PRINT)); return Boolean.TRUE.equals(serializer.getDomConfig().getParameter(PARAM_PRETTY_PRINT));
} }
private void setXMLDeclaration(boolean pXMLDeclaration) { private void setXMLDeclaration(boolean pXMLDeclaration) {
mSerializer.getDomConfig().setParameter(PARAM_XML_DECLARATION, pXMLDeclaration); serializer.getDomConfig().setParameter(PARAM_XML_DECLARATION, pXMLDeclaration);
} }
/** /**
@@ -142,7 +142,7 @@ public final class DOMSerializer {
private void serializeImpl(final Node pNode, final boolean pOmitDecl) { private void serializeImpl(final Node pNode, final boolean pOmitDecl) {
setXMLDeclaration(pOmitDecl); setXMLDeclaration(pOmitDecl);
mSerializer.write(pNode, mOutput); serializer.write(pNode, output);
} }
private static class Support { private static class Support {

View File

@@ -65,22 +65,22 @@ public class XMLSerializer {
// Store user options here too // Store user options here too
// TODO: Push/pop? // TODO: Push/pop?
private final OutputStream mOutput; private final OutputStream output;
private final Charset mEncoding; private final Charset encoding;
private final SerializationContext mContext; private final SerializationContext context;
public XMLSerializer(final OutputStream pOutput, final String pEncoding) { public XMLSerializer(final OutputStream pOutput, final String pEncoding) {
mOutput = pOutput; output = pOutput;
mEncoding = Charset.forName(pEncoding); encoding = Charset.forName(pEncoding);
mContext = new SerializationContext(); context = new SerializationContext();
} }
public final void setIndentation(String pIndent) { public final void setIndentation(String pIndent) {
mContext.indent = pIndent != null ? pIndent : " "; context.indent = pIndent != null ? pIndent : " ";
} }
public final void setStripComments(boolean pStrip) { public final void setStripComments(boolean pStrip) {
mContext.stripComments = pStrip; context.stripComments = pStrip;
} }
/** /**
@@ -101,12 +101,12 @@ public class XMLSerializer {
* @param pWriteXMLDeclaration {@code true} if the XML declaration should be included, otherwise {@code false}. * @param pWriteXMLDeclaration {@code true} if the XML declaration should be included, otherwise {@code false}.
*/ */
public void serialize(final Node pRootNode, final boolean pWriteXMLDeclaration) { public void serialize(final Node pRootNode, final boolean pWriteXMLDeclaration) {
PrintWriter out = new PrintWriter(new OutputStreamWriter(mOutput, mEncoding)); PrintWriter out = new PrintWriter(new OutputStreamWriter(output, encoding));
try { try {
if (pWriteXMLDeclaration) { if (pWriteXMLDeclaration) {
writeXMLDeclaration(out); writeXMLDeclaration(out);
} }
writeXML(out, pRootNode, mContext.copy()); writeXML(out, pRootNode, context.copy());
} }
finally { finally {
out.flush(); out.flush();
@@ -115,7 +115,7 @@ public class XMLSerializer {
private void writeXMLDeclaration(final PrintWriter pOut) { private void writeXMLDeclaration(final PrintWriter pOut) {
pOut.print("<?xml version=\"1.0\" encoding=\""); pOut.print("<?xml version=\"1.0\" encoding=\"");
pOut.print(mEncoding.name()); pOut.print(encoding.name());
pOut.println("\"?>"); pOut.println("\"?>");
} }