changeset 159:e743b853efca

servlet version 1.16a4 - rather experimental - new Texter servlet for sending text - reads and caches text files in DocuDirCache - DocuFile renamed to ImageFile (-Set) - new TextFile
author robcast
date Tue, 16 Sep 2003 18:32:00 +0200
parents e9a81ac446cb
children aecb57fb8f96
files servlet/src/digilib/image/DocuImage.java servlet/src/digilib/image/DocuImageImpl.java servlet/src/digilib/image/DocuInfo.java servlet/src/digilib/image/ImageLoaderDocuImage.java servlet/src/digilib/image/ImageLoaderDocuInfo.java servlet/src/digilib/image/ImageLoaderImageInfoDocuInfo.java servlet/src/digilib/image/ImageSize.java servlet/src/digilib/image/JAIDocuImage.java servlet/src/digilib/image/JAIImageLoaderDocuImage.java servlet/src/digilib/image/JIMIDocuImage.java servlet/src/digilib/io/Directory.java servlet/src/digilib/io/DocuDirCache.java servlet/src/digilib/io/DocuDirectory.java servlet/src/digilib/io/DocuDirent.java servlet/src/digilib/io/DocuFile.java servlet/src/digilib/io/DocuFileset.java servlet/src/digilib/io/FileOps.java servlet/src/digilib/io/ImageFile.java servlet/src/digilib/io/ImageFileset.java
diffstat 19 files changed, 973 insertions(+), 733 deletions(-) [+]
line wrap: on
line diff
--- a/servlet/src/digilib/image/DocuImage.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/image/DocuImage.java	Tue Sep 16 18:32:00 2003 +0200
@@ -23,7 +23,7 @@
 import java.awt.Rectangle;
 import java.io.OutputStream;
 
-import digilib.io.DocuFile;
+import digilib.io.ImageFile;
 import digilib.io.FileOpException;
 
 /** The basic class for the representation of a digilib image.
@@ -46,7 +46,7 @@
 	 * @param f Image File.
 	 * @throws FileOpException Exception thrown if any error occurs.
 	 */
-	public void loadImage(DocuFile f) throws FileOpException;
+	public void loadImage(ImageFile f) throws FileOpException;
 
 	/** This DocuImage support the loadSubImage operation.
 	 * 
@@ -61,7 +61,7 @@
 	 * @param subsample
 	 * @throws FileOpException
 	 */
-	public void loadSubimage(DocuFile f, Rectangle region, int subsample)
+	public void loadSubimage(ImageFile f, Rectangle region, int subsample)
 		throws FileOpException;
 
 	/** Writes the current image to a ServletResponse.
--- a/servlet/src/digilib/image/DocuImageImpl.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/image/DocuImageImpl.java	Tue Sep 16 18:32:00 2003 +0200
@@ -23,7 +23,7 @@
 import java.awt.Rectangle;
 
 import digilib.Utils;
-import digilib.io.DocuFile;
+import digilib.io.ImageFile;
 import digilib.io.FileOpException;
 
 /** Simple abstract implementation of the <code>DocuImage</code> interface.
@@ -140,7 +140,7 @@
 		return false;
 	}
 
-	public void loadSubimage(DocuFile f, Rectangle region, int subsample)
+	public void loadSubimage(ImageFile f, Rectangle region, int subsample)
 		throws FileOpException {
 		// empty implementation
 	}
--- a/servlet/src/digilib/image/DocuInfo.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/image/DocuInfo.java	Tue Sep 16 18:32:00 2003 +0200
@@ -22,7 +22,7 @@
 
 import java.io.IOException;
 
-import digilib.io.DocuFile;
+import digilib.io.ImageFile;
 
 /**
  * @author casties
@@ -30,15 +30,15 @@
  */
 public interface DocuInfo {
 
-	/** Checks the size and type of the DocuFile f.
+	/** Checks the size and type of the ImageFile f.
 	 * 
-	 * The image size and type of the DocuFile f is determined and stored in
-	 * the DocuFile object. Returns true if successfull.
+	 * The image size and type of the ImageFile f is determined and stored in
+	 * the ImageFile object. Returns true if successfull.
 	 * 
-	 * @param f DocuFile to be checked.
+	 * @param f ImageFile to be checked.
 	 * @return boolean true if check was successfull.
 	 * @throws FileOpException Exception thrown on error.
 	 */
-	public boolean checkFile(DocuFile f) throws IOException;
+	public boolean checkFile(ImageFile f) throws IOException;
 
 }
--- a/servlet/src/digilib/image/ImageLoaderDocuImage.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/image/ImageLoaderDocuImage.java	Tue Sep 16 18:32:00 2003 +0200
@@ -38,7 +38,7 @@
 import javax.imageio.ImageReader;
 import javax.imageio.stream.ImageInputStream;
 
-import digilib.io.DocuFile;
+import digilib.io.ImageFile;
 import digilib.io.FileOpException;
 
 /** Implementation of DocuImage using the ImageLoader API of Java 1.4 and Java2D. */
@@ -99,9 +99,9 @@
 	}
 
 	/* load image file */
-	public void loadImage(DocuFile f) throws FileOpException {
+	public void loadImage(ImageFile f) throws FileOpException {
 		util.dprintln(10, "loadImage!");
-		System.gc();
+		//System.gc();
 		try {
 			img = ImageIO.read(f.getFile());
 			if (img == null) {
@@ -116,13 +116,13 @@
 	/** Get an ImageReader for the image file.
 	 * 
 	 */
-	public void preloadImage(DocuFile f) throws IOException {
+	public void preloadImage(ImageFile f) throws IOException {
 		if (reader != null) {
 			// clean up old reader
 			reader.dispose();
 			reader = null;
 		}
-		System.gc();
+		//System.gc();
 		RandomAccessFile rf = new RandomAccessFile(f.getFile(), "r");
 		ImageInputStream istream = ImageIO.createImageInputStream(rf);
 		//Iterator readers = ImageIO.getImageReaders(istream);
@@ -145,9 +145,9 @@
 	}
 
 	/* Load an image file into the Object. */
-	public void loadSubimage(DocuFile f, Rectangle region, int prescale)
+	public void loadSubimage(ImageFile f, Rectangle region, int prescale)
 		throws FileOpException {
-		System.gc();
+		//System.gc();
 		try {
 			if ((reader == null) || (imgFile != f.getFile())) {
 				preloadImage(f);
--- a/servlet/src/digilib/image/ImageLoaderDocuInfo.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/image/ImageLoaderDocuInfo.java	Tue Sep 16 18:32:00 2003 +0200
@@ -23,7 +23,7 @@
 
 import java.io.IOException;
 
-import digilib.io.DocuFile;
+import digilib.io.ImageFile;
 import digilib.io.FileOps;
 
 /**
@@ -34,8 +34,8 @@
 
 	private ImageLoaderDocuImage img = new ImageLoaderDocuImage();
 
-	/* check image size and type and store in DocuFile f */
-	public boolean checkFile(DocuFile f) throws IOException {
+	/* check image size and type and store in ImageFile f */
+	public boolean checkFile(ImageFile f) throws IOException {
 		ImageLoaderDocuImage img = new ImageLoaderDocuImage();
 		img.preloadImage(f);
 		img.reader = img.reader;
--- a/servlet/src/digilib/image/ImageLoaderImageInfoDocuInfo.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/image/ImageLoaderImageInfoDocuInfo.java	Tue Sep 16 18:32:00 2003 +0200
@@ -22,6 +22,7 @@
 
 import ImageInfo;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.util.Iterator;
@@ -30,9 +31,9 @@
 import javax.imageio.ImageReader;
 import javax.imageio.stream.ImageInputStream;
 
-import digilib.io.DocuFile;
 import digilib.io.FileOpException;
 import digilib.io.FileOps;
+import digilib.io.ImageFile;
 
 /**
  * @author casties
@@ -40,9 +41,13 @@
  */
 public class ImageLoaderImageInfoDocuInfo implements DocuInfo {
 
-	/* check image size and type and store in DocuFile f */
-	public boolean checkFile(DocuFile f) throws IOException {
-		RandomAccessFile raf = new RandomAccessFile(f.getFile(), "r");
+	/* check image size and type and store in ImageFile f */
+	public boolean checkFile(ImageFile imgf) throws IOException {
+		File f = imgf.getFile();
+		if (f == null) {
+			throw new IOException("File not found!");
+		}
+		RandomAccessFile raf = new RandomAccessFile(f, "r");
 		// set up ImageInfo object
 		ImageInfo iif = new ImageInfo();
 		iif.setInput(raf);
@@ -52,8 +57,8 @@
 		if (iif.check()) {
 			ImageSize d =
 				new ImageSize(iif.getWidth(), iif.getHeight());
-			f.setSize(d);
-			f.setMimetype(iif.getMimeType());
+			imgf.setSize(d);
+			imgf.setMimetype(iif.getMimeType());
 			raf.close();
 		} else {
 			// else use ImageReader
@@ -73,10 +78,10 @@
 			reader.setInput(istream);
 			ImageSize d =
 				new ImageSize(reader.getWidth(0), reader.getHeight(0));
-			f.setSize(d);
+			imgf.setSize(d);
 			String t = reader.getFormatName();
-			t = FileOps.mimeForFile(f.getFile());
-			f.setMimetype(t);
+			t = FileOps.mimeForFile(f);
+			imgf.setMimetype(t);
 			// dispose the reader to free resources
 			reader.dispose();
 		}
--- a/servlet/src/digilib/image/ImageSize.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/image/ImageSize.java	Tue Sep 16 18:32:00 2003 +0200
@@ -1,4 +1,4 @@
-/* DocuFile.java -- digilib image file class.
+/* ImageFile.java -- digilib image file class.
 
   Digital Image Library servlet components
 
--- a/servlet/src/digilib/image/JAIDocuImage.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/image/JAIDocuImage.java	Tue Sep 16 18:32:00 2003 +0200
@@ -35,7 +35,7 @@
 import javax.media.jai.operator.TransposeType;
 
 import digilib.Utils;
-import digilib.io.DocuFile;
+import digilib.io.ImageFile;
 import digilib.io.FileOpException;
 
 /** A DocuImage implementation using Java Advanced Imaging Library. */
@@ -56,7 +56,7 @@
 	}
 
 	/* Load an image file into the Object. */
-	public void loadImage(DocuFile f) throws FileOpException {
+	public void loadImage(ImageFile f) throws FileOpException {
 		System.gc();
 		img = JAI.create("fileload", f.getFile().getAbsolutePath());
 		if (img == null) {
--- a/servlet/src/digilib/image/JAIImageLoaderDocuImage.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/image/JAIImageLoaderDocuImage.java	Tue Sep 16 18:32:00 2003 +0200
@@ -34,7 +34,7 @@
 import javax.imageio.stream.ImageInputStream;
 import javax.media.jai.JAI;
 
-import digilib.io.DocuFile;
+import digilib.io.ImageFile;
 import digilib.io.FileOpException;
 
 /** DocuImage implementation using the Java Advanced Imaging API and the ImageLoader
@@ -81,7 +81,7 @@
 	}
 
 	/* Load an image file into the Object. */
-	public void loadImage(DocuFile f) throws FileOpException {
+	public void loadImage(ImageFile f) throws FileOpException {
 		System.gc();
 		img = JAI.create("ImageRead", f.getFile().getAbsolutePath());
 		if (img == null) {
@@ -91,7 +91,7 @@
 	}
 
 	/* Get an ImageReader for the image file. */
-	public void preloadImage(DocuFile f) throws IOException {
+	public void preloadImage(ImageFile f) throws IOException {
 		System.gc();
 		RandomAccessFile rf = new RandomAccessFile(f.getFile(), "r");
 		ImageInputStream istream = ImageIO.createImageInputStream(rf);
@@ -106,7 +106,7 @@
 	}
 
 	/* Load an image file into the Object. */
-	public void loadSubimage(DocuFile f, Rectangle region, int prescale)
+	public void loadSubimage(ImageFile f, Rectangle region, int prescale)
 		throws FileOpException {
 		System.gc();
 		try {
--- a/servlet/src/digilib/image/JIMIDocuImage.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/image/JIMIDocuImage.java	Tue Sep 16 18:32:00 2003 +0200
@@ -32,7 +32,7 @@
 import com.sun.jimi.core.raster.JimiRasterImage;
 
 import digilib.Utils;
-import digilib.io.DocuFile;
+import digilib.io.ImageFile;
 import digilib.io.FileOpException;
 
 /** Implementation of DocuImage using the JIMI image Library. */
@@ -53,7 +53,7 @@
 	/**
 	 *  load image file
 	 */
-	public void loadImage(DocuFile f) throws FileOpException {
+	public void loadImage(ImageFile f) throws FileOpException {
 		System.gc();
 		try {
 			img = Jimi.getRasterImage(f.getFile().toURL());
--- a/servlet/src/digilib/io/Directory.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/io/Directory.java	Tue Sep 16 18:32:00 2003 +0200
@@ -50,7 +50,8 @@
 
 	/** Constructor taking a File object and a parent.
 	 * 
-	 * @param d
+	 * @param dir
+	 * @param parent
 	 */
 	public Directory(File dir, Directory parent) {
 		this.dir = dir;
--- a/servlet/src/digilib/io/DocuDirCache.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/io/DocuDirCache.java	Tue Sep 16 18:32:00 2003 +0200
@@ -23,23 +23,37 @@
 
 import java.io.File;
 import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
 
 /**
  * @author casties
  */
 public class DocuDirCache {
 
-	// HashMap of directories
+	/** HashMap of directories */
 	private HashMap map = null;
-	// names of base directories
+	/** names of base directories */
 	private String[] baseDirNames = null;
-	// number of files in the whole cache (approximate)
+	/** array of allowed file classes (image/text) */
+	private int[] fileClasses = null;
+	/** number of files in the whole cache (approximate) */
 	private long numFiles = 0;
-	// number of cache hits
+	/** number of cache hits */
 	private long hits = 0;
-	// number of cache misses
+	/** number of cache misses */
 	private long misses = 0;
 
+	/** Constructor with array of base directory names and file classes.
+	 *  
+	 * @param bd base directory names
+	 */
+	public DocuDirCache(String[] bd, int[] fileClasses) {
+		baseDirNames = bd;
+		map = new HashMap();
+		this.fileClasses = fileClasses;
+	}
 	/** Constructor with array of base directory names.
 	 *  
 	 * @param bd base directory names
@@ -47,6 +61,9 @@
 	public DocuDirCache(String[] bd) {
 		baseDirNames = bd;
 		map = new HashMap();
+		// default file class is CLASS_IMAGE
+		fileClasses = new int[1];
+		fileClasses[0] = FileOps.CLASS_IMAGE;
 	}
 
 	/** The number of directories in the cache.
@@ -63,7 +80,7 @@
 	public void put(DocuDirectory newdir) {
 		String s = newdir.getDirName();
 		if (map.containsKey(s)) {
-			System.out.println("Baah, duplicate key in DocuDirectory.put!");
+			System.out.println("Baah, duplicate key in DocuDirCache.put!");
 		} else {
 			map.put(s, newdir);
 			numFiles += newdir.size();
@@ -87,12 +104,37 @@
 			}
 			newDir.setParent(pd);
 		}
-		// update dir in the end
-		newDir.readParentMeta();
 	}
 
-	/** Returns the DocuFileset with the pathname <code>fn</code> and the 
-	 * index <code>in</code>.
+	/** Get a list with all children of a directory.
+	 * 
+	 * Returns a List of DocuDirectory's.
+	 * Returns an empty List if the directory has no children.
+	 * If recurse is false then only direct children are returned.
+	 * 
+	 * @param dirname
+	 * @param recurse find all children and their children.
+	 * @return
+	 */
+	public List getChildren(String dirname, boolean recurse) {
+		List l = new LinkedList();
+		for (Iterator i = map.keySet().iterator(); i.hasNext(); ) {
+			DocuDirectory dd = (DocuDirectory)i.next();
+			if (recurse) {
+				if (dd.getDirName().startsWith(dirname)) {
+					l.add(dd);
+				}
+			} else {
+				if (dd.getParentDirName().equals(dirname)) {
+					l.add(dd);
+				}
+			}
+		}
+		return l;
+	}
+
+	/** Returns the ImageFileset with the pathname <code>fn</code> and the 
+	 * index <code>in</code> and the class <code>fc</code>.
 	 * 
 	 * If <code>fn</code> is a file then the corresponding Fileset is 
 	 * returned and the index is ignored.
@@ -101,7 +143,7 @@
 	 * @param in file index
 	 * @return 
 	 */
-	public DocuFileset getFileset(String fn, int in) {
+	public DocuDirent getFile(String fn, int in, int fc) {
 		DocuDirectory dd;
 		// file number is 1-based, vector index is 0-based
 		int n = in - 1;
@@ -140,7 +182,7 @@
 						misses--;
 					}
 					// get the file's index
-					n = dd.indexOf(f.getName());
+					n = dd.indexOf(f.getName(), fc);
 				} else {
 					// it's not even a file :-(
 					return null;
@@ -153,7 +195,7 @@
 		dd.refresh();
 		if (dd.isValid()) {
 			try {
-				return dd.get(n);
+				return dd.get(n, fc);
 			} catch (ArrayIndexOutOfBoundsException e) {
 			}
 		}
@@ -253,4 +295,18 @@
 		return misses;
 	}
 
+	/**
+	 * @return
+	 */
+	public int[] getFileClasses() {
+		return fileClasses;
+	}
+
+	/**
+	 * @param fileClasses
+	 */
+	public void setFileClasses(int[] fileClasses) {
+		this.fileClasses = fileClasses;
+	}
+	
 }
--- a/servlet/src/digilib/io/DocuDirectory.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/io/DocuDirectory.java	Tue Sep 16 18:32:00 2003 +0200
@@ -27,6 +27,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 
 import org.xml.sax.SAXException;
 
@@ -35,9 +36,9 @@
  */
 public class DocuDirectory extends Directory {
 
-	// list of files (DocuFileSet)
-	private ArrayList list = null;
-	// directory object is valid (has been read)
+	// list of files (DocuDirent)
+	private ArrayList[] list = null;
+	// directory object is valid (exists on disk)
 	private boolean isValid = false;
 	// reference of the parent DocuDirCache
 	private DocuDirCache cache = null;
@@ -52,29 +53,37 @@
 	// time the file system directory was last modified
 	private long dirMTime = 0;
 
-	/*
-	 * constructors
-	 */
-
-	/** Constructor with directory path and a parent DocuDirCache.
+	/** Constructor with digilib directory path and a parent DocuDirCache.
 	 * 
-	 * Reads the directory at the given path appended to the base directories 
-	 * from the cache.
+	 * Directory names at the given path are appended to the base directories 
+	 * from the cache. The directory is checked on disk and isValid is set. 
+	 * If read is true the directory is read and filled.
 	 * 
 	 * @see readDir
 	 *  
 	 * @param path digilib directory path name
 	 * @param bd array of base directory names
+	 * @param read the directory is read and filled
 	 */
 	public DocuDirectory(String path, DocuDirCache cache) {
 		this.dirName = path;
 		this.cache = cache;
-		readDir();
+		initDir();
+		checkDir();
 	}
 
-	/*
-	 * other stuff
+	/** Sets and checks the dir object.
+	 * 
 	 */
+	protected void initDir() {
+		String baseDirName = cache.getBaseDirNames()[0];
+		// clear directory first
+		list = new ArrayList[FileOps.NUM_CLASSES];
+		isValid = false;
+		dirMTime = 0;
+		// the first directory has to exist
+		dir = new File(baseDirName, dirName);
+	}
 
 	/** The digilib name of the parent directory.
 	 * 
@@ -93,19 +102,54 @@
 	 * 
 	 */
 	public int size() {
-		return (list != null) ? list.size() : 0;
+		return ((list != null)&&(list[0] != null)) ? list[0].size() : 0;
 	}
 
-	/** Returns the DocuFile at the index.
+	/** number of files of this class in this directory.
+	 * 
+	 * @param fc fileClass
+	 */
+	public int size(int fc) {
+		return ((list != null)&&(list[fc] != null)) ? list[fc].size() : 0;
+	}
+
+	/** Returns the ImageFile at the index.
 	 * 
 	 * @param index
 	 * @return
 	 */
-	public DocuFileset get(int index) {
-		if ((list == null) || (index >= list.size())) {
+	public ImageFileset get(int index) {
+		if ((list == null) || (list[0] != null) || (index >= list[0].size())) {
 			return null;
 		}
-		return (DocuFileset) list.get(index);
+		return (ImageFileset) list[0].get(index);
+	}
+
+	/** Returns the file of the class at the index.
+	 * 
+	 * @param index
+	 * @param fc fileClass
+	 * @return
+	 */
+	public DocuDirent get(int index, int fc) {
+		if ((list == null) || (list[fc] == null) || (index >= list[fc].size())) {
+			return null;
+		}
+		return (DocuDirent) list[fc].get(index);
+	}
+
+	/** Checks if the directory exists on the filesystem.
+	 * 
+	 * Sets isValid.
+	 * 
+	 * @return
+	 */
+	public boolean checkDir() {
+		if (dir == null) {
+			initDir();
+		}
+		isValid = dir.isDirectory();
+		return isValid;
 	}
 
 	/** Read the filesystem directory and fill this object.
@@ -115,91 +159,64 @@
 	 * @return boolean the directory exists
 	 */
 	public boolean readDir() {
+		// list of base dirs from the parent cache
 		String[] baseDirNames = cache.getBaseDirNames();
 		// first file extension to try for scaled directories
-		String fext = null;
-		// clear directory first
-		list = null;
-		isValid = false;
+		String scalext = null;
 		// number of base dirs
 		int nb = baseDirNames.length;
 		// array of base dirs
 		Directory[] dirs = new Directory[nb];
-		// the first directory has to exist
-		dir = new File(baseDirNames[0], dirName);
+		// check directory first
+		checkDir();
+		if (!isValid) {
+			return false;
+		}
+		// first entry is this directory
+		dirs[0] = this;
+		// fill array with the remaining directories
+		for (int j = 1; j < nb; j++) {
+			File d = new File(baseDirNames[j], dirName);
+			if (d.isDirectory()) {
+				dirs[j] = new Directory(d);
+			}
+		}
 
-		if (dir.isDirectory()) {
-			// fill array with the remaining directories
-			for (int j = 1; j < nb; j++) {
-				File d = new File(baseDirNames[j], dirName);
-				if (d.isDirectory()) {
-					dirs[j] = new Directory(d);
-				}
-			}
-
-			File[] fl = dir.listFiles(new FileOps.ImageFileFilter());
+		// go through all file classes
+		for (int nc = 0; nc < FileOps.NUM_CLASSES; nc++) {
+			int fc = cache.getFileClasses()[nc];
+			File[] fl = dir.listFiles(FileOps.filterForClass(fc));
 			if (fl == null) {
 				// not a directory
 				return false;
 			}
-			// number of image files in the directory
+			// number of files in the directory
 			int nf = fl.length;
 			if (nf > 0) {
 				// create new list
-				list = new ArrayList(nf);
-
+				list[fc] = new ArrayList(nf);
 				// sort the file names alphabetically and iterate the list
 				Arrays.sort(fl);
 				for (int i = 0; i < nf; i++) {
-					String fn = fl[i].getName();
-					String fnx = fn.substring(0, fn.lastIndexOf('.') + 1);
-					// add the first DocuFile to a new DocuFileset 
-					DocuFileset fs = new DocuFileset(nb);
-					fs.add(new DocuFile(fn, fs, this));
-					// iterate the remaining base directories
-					for (int j = 1; j < nb; j++) {
-						if (dirs[j] == null) {
-							continue;
-						}
-						File f;
-						if (fext != null) {
-							// use the last extension
-							f = new File(dirs[j].getDir(), fnx + fext);
-						} else {
-							// try the same filename as the original
-							f = new File(dirs[j].getDir(), fn);
-						}
-						// if the file exists, add to the DocuFileset
-						if (f.canRead()) {
-							fs.add(new DocuFile(f.getName(), fs, dirs[j]));
-						} else {
-							// try other file extensions
-							Iterator exts = FileOps.getImageExtensionIterator();
-							while (exts.hasNext()) {
-								String s = (String) exts.next();
-								f = new File(dirs[j].getDir(), fnx + s);
-								// if the file exists, add to the DocuFileset
-								if (f.canRead()) {
-									fs.add(
-										new DocuFile(f.getName(), fs, dirs[j]));
-									fext = s;
-									break;
-								}
-							}
-						}
+					DocuDirent f = null;
+					// what class of file do we have?
+					if (fc == FileOps.CLASS_IMAGE) {
+						// image file
+						f = new ImageFileset(dirs, fl[i], scalext);
+					} else if (fc == FileOps.CLASS_TEXT) {
+						// text file
+						f = new TextFile(fl[i]);
 					}
-					// add the fileset to our list
-					list.add(fs);
-					fs.setParent(this);
+					// add the file to our list
+					list[fc].add(f);
+					f.setParent(this);
 				}
 			}
-			dirMTime = dir.lastModified();
-			isValid = true;
-			// read metadata as well
-			readMeta();
 		}
+		dirMTime = dir.lastModified();
+		// read metadata as well
+		readMeta();
 		return isValid;
-
 	}
 
 	/** Check to see if the directory has been modified and reread if necessary.
@@ -275,23 +292,41 @@
 	 * 
 	 * @param fileMeta
 	 * @param relPath
+	 * @param fc fileClass
 	 */
-	public void readFileMeta(HashMap fileMeta, String relPath) {
+	protected void readFileMeta(HashMap fileMeta, String relPath) {
 		if (list == null) {
 			// there are no files
 			return;
 		}
 		String path = (relPath != null) ? (relPath + "/") : "";
-		// iterate through the list of files in this directory
-		for (Iterator i = list.iterator(); i.hasNext();) {
-			DocuFileset df = (DocuFileset) i.next();
-			// prepend path to the filename
-			String fn = path + df.getName();
-			// look up meta for this file and remove from dir
-			HashMap meta = (HashMap) fileMeta.remove(fn);
-			if (meta != null) {
-				// store meta in file
-				df.setFileMeta(meta);
+		// go through all file classes
+		for (int nc = 0; nc < list.length; nc++) {
+			int fc = cache.getFileClasses()[nc];
+			if (list[fc] == null) {
+				continue;
+			}
+			// iterate through the list of files in this directory
+			for (Iterator i = list[fc].iterator(); i.hasNext();) {
+				DocuDirent f = (DocuDirent) i.next();
+				// prepend path to the filename
+				String fn = path + f.getName();
+				// look up meta for this file and remove from dir
+				HashMap meta = (HashMap) fileMeta.remove(fn);
+				if (meta != null) {
+					// store meta in file
+					f.setFileMeta(meta);
+				}
+			}
+		}
+	}
+
+	protected void notifyChildMeta(HashMap childmeta) {
+		List children = cache.getChildren(this.dirName, true);
+		if (children.size() > 0) {
+			for (Iterator i = children.iterator(); i.hasNext();) {
+				// TODO: finish this!
+				//((DocuDirectory) i.next()).readFileMeta()
 			}
 		}
 	}
@@ -312,13 +347,27 @@
 	 * its index. Returns -1 if the file cannot be found. 
 	 *  
 	 * @param fn filename
+	 * @param fc file class
 	 * @return int index of file <code>fn</code>
 	 */
 	public int indexOf(String fn) {
+		int fc = FileOps.classForFilename(fn);
+		return indexOf(fn, fc);
+	}
+	
+	/** Searches for the file with the name <code>fn</code> and class fc.
+	 * 
+	 * Searches the directory for the file with the name <code>fn</code> and returns 
+	 * its index. Returns -1 if the file cannot be found. 
+	 *  
+	 * @param fn filename
+	 * @return int index of file <code>fn</code>
+	 */
+	public int indexOf(String fn, int fc) {
 		// linear search -> worst performance
-		int n = list.size();
+		int n = list[fc].size();
 		for (int i = 0; i < n; i++) {
-			DocuFileset fs = (DocuFileset) list.get(i);
+			ImageFileset fs = (ImageFileset) list[fc].get(i);
 			if (fs.getName().equals(fn)) {
 				return i;
 			}
@@ -326,18 +375,35 @@
 		return -1;
 	}
 
-	/** Finds the DocuFileset with the name <code>fn</code>.
+	/** Finds the ImageFileset with the name <code>fn</code>.
 	 * 
-	 * Searches the directory for the DocuFileset with the name <code>fn</code> and returns 
+	 * Searches the directory for the ImageFileset with the name <code>fn</code> and returns 
 	 * it. Returns null if the file cannot be found. 
 	 *  
 	 * @param fn filename
-	 * @return DocuFileset
+	 * @return ImageFileset
 	 */
-	public DocuFileset find(String fn) {
-		int i = indexOf(fn);
+	public ImageFileset find(String fn) {
+		int fc = FileOps.classForFilename(fn);
+		int i = indexOf(fn, fc);
 		if (i >= 0) {
-			return (DocuFileset) list.get(i);
+			return (ImageFileset) list[0].get(i);
+		}
+		return null;
+	}
+
+	/** Finds the ImageFileset with the name <code>fn</code> and class <code>fc</code>.
+	 * 
+	 * Searches the directory for the ImageFileset with the name <code>fn</code> and returns 
+	 * it. Returns null if the file cannot be found. 
+	 *  
+	 * @param fn filename
+	 * @return ImageFileset
+	 */
+	public ImageFileset find(String fn, int fc) {
+		int i = indexOf(fn, fc);
+		if (i >= 0) {
+			return (ImageFileset) list[fc].get(i);
 		}
 		return null;
 	}
@@ -349,13 +415,22 @@
 		return dirName;
 	}
 
-	/**
+	/** The directory is valid (exists on disk).
+	 * 
 	 * @return boolean
 	 */
 	public boolean isValid() {
 		return isValid;
 	}
 
+	/** The directory has been read from disk.
+	 * 
+	 * @return
+	 */
+	public boolean isRead() {
+		return (dirMTime != 0);
+	}
+
 	/**
 	 * @return long
 	 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/DocuDirent.java	Tue Sep 16 18:32:00 2003 +0200
@@ -0,0 +1,136 @@
+/* DocuDirent.java --  Abstract directory entry in a DocuDirectory
+
+  Digital Image Library servlet components
+
+  Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
+
+  This program is free software; you can redistribute  it and/or modify it
+  under  the terms of  the GNU General  Public License as published by the
+  Free Software Foundation;  either version 2 of the  License, or (at your
+  option) any later version.
+   
+  Please read license.txt for the full details. A copy of the GPL
+  may be found at http://www.gnu.org/copyleft/lgpl.html
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ * Created on 15.09.2003 by casties
+ *
+ */
+package digilib.io;
+
+import java.io.File;
+import java.util.HashMap;
+
+/** Abstract directory entry in a DocuDirectory.
+ * 
+ * @author casties
+ *
+ */
+public abstract class DocuDirent {
+
+	/** the file class of this file */
+	protected static int fileClass = FileOps.CLASS_NONE; 
+	/** HashMap with metadata */
+	protected HashMap fileMeta = null;
+	/** Is the Metadata valid */
+	protected boolean metaChecked = false;
+	/** the parent directory */
+	protected Directory parent = null;
+
+	/** Checks metadata and does something with it.
+	 * 
+	 */
+	public abstract void checkMeta();
+
+	/**
+	 * gets the (default) File
+	 * @return
+	 */
+	public abstract File getFile();
+
+	/** Reads meta-data for this Fileset if there is any.
+	 * 
+	 */
+	public void readMeta() {
+		if ((fileMeta != null) || (getFile() != null)) {
+			// there is already metadata or there is no file
+			return;
+		}
+		// metadata is in the file {filename}.meta
+		String fn = getFile().getAbsolutePath();
+		File mf = new File(fn + ".meta");
+		if (mf.canRead()) {
+			XMLMetaLoader ml = new XMLMetaLoader();
+			try {
+				// read meta file
+				HashMap meta = ml.loadURL(mf.getAbsolutePath());
+				if (meta == null) {
+					return;
+				}
+				fileMeta = (HashMap) meta.get(getName());
+			} catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+	}
+
+	/** The name of the (hires) image file.
+	 * 
+	 * @return
+	 */
+	public String getName() {
+		File f = getFile();
+		return (f != null) ? f.getName() : null;
+	}
+
+	/** Returns the parent DocuDirectory.
+	 * 
+	 * @return DocuDirectory
+	 */
+	public Directory getParent() {
+		return parent;
+	}
+
+	/**
+	 * Sets the parent.
+	 * @param parent The parent to set
+	 */
+	public void setParent(Directory parent) {
+		this.parent = parent;
+	}
+
+	/** Returns the meta-data for this fileset.
+	 * 
+	 * @return HashMap
+	 */
+	public HashMap getFileMeta() {
+		return fileMeta;
+	}
+
+	/**
+	 * Sets the fileMeta.
+	 * @param fileMeta The fileMeta to set
+	 */
+	public void setFileMeta(HashMap fileMeta) {
+		this.fileMeta = fileMeta;
+	}
+
+	/**
+	 * @return
+	 */
+	public boolean isMetaChecked() {
+		return metaChecked;
+	}
+
+	/**
+	 * @return
+	 */
+	public static int getFileClass() {
+		return fileClass;
+	}
+
+}
--- a/servlet/src/digilib/io/DocuFile.java	Tue Sep 16 18:26:31 2003 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-/* DocuFile.java -- digilib image file class.
-
-  Digital Image Library servlet components
-
-  Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
-
-  This program is free software; you can redistribute  it and/or modify it
-  under  the terms of  the GNU General  Public License as published by the
-  Free Software Foundation;  either version 2 of the  License, or (at your
-  option) any later version.
-   
-  Please read license.txt for the full details. A copy of the GPL
-  may be found at http://www.gnu.org/copyleft/lgpl.html
-
-  You should have received a copy of the GNU General Public License
-  along with this program; if not, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- * Created on 25.02.2003
- */
- 
-package digilib.io;
-
-import java.io.File;
-
-import digilib.image.ImageSize;
-
-/**
- * @author casties
- */
-public class DocuFile {
-	
-	// file object
-	private String filename = null;
-	// parent DocuFileset
-	private DocuFileset parent = null;
-	// parent directory
-	private Directory dir = null;
-	// mime file type
-	private String mimetype = null;
-	// image size in pixels
-	private ImageSize pixelSize = null;
-
-	public DocuFile(String fn, DocuFileset parent, Directory dir) {
-		this.filename = fn;
-		this.parent = parent;
-		this.dir = dir;
-	}
-	
-	public DocuFile(String fn) {
-		File f = new File(fn);
-		this.dir = new Directory(f.getParentFile());
-		this.filename = f.getName();
-	}
-	
-	/** Returns the file name (without path).
-	 * 
-	 * @return
-	 */
-	public String getName() {
-		return filename;
-	}
-
-
-	/**
-	 * @return File
-	 */
-	public File getFile() {
-		File f = new File(dir.getDir(), filename);
-		return f;
-	}
-
-	/**
-	 * @return ImageSize
-	 */
-	public ImageSize getSize() {
-		return pixelSize;
-	}
-
-	/**
-	 * @return String
-	 */
-	public String getMimetype() {
-		return mimetype;
-	}
-
-	/**
-	 * Sets the imageSize.
-	 * @param imageSize The imageSize to set
-	 */
-	public void setSize(ImageSize imageSize) {
-		this.pixelSize = imageSize;
-	}
-
-	/**
-	 * Sets the mimetype.
-	 * @param mimetype The mimetype to set
-	 */
-	public void setMimetype(String mimetype) {
-		this.mimetype = mimetype;
-	}
-
-	/**
-	 * @return DocuFileset
-	 */
-	public DocuFileset getParent() {
-		return parent;
-	}
-
-	/**
-	 * Sets the parent.
-	 * @param parent The parent to set
-	 */
-	public void setParent(DocuFileset parent) {
-		this.parent = parent;
-	}
-
-	/**
-	 * @return boolean
-	 */
-	public boolean isChecked() {
-		return (pixelSize != null);
-	}
-
-}
--- a/servlet/src/digilib/io/DocuFileset.java	Tue Sep 16 18:26:31 2003 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,347 +0,0 @@
-/* DocuFileset -- digilib image file info class.
-
-  Digital Image Library servlet components
-
-  Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
-
-  This program is free software; you can redistribute  it and/or modify it
-  under  the terms of  the GNU General  Public License as published by the
-  Free Software Foundation;  either version 2 of the  License, or (at your
-  option) any later version.
-   
-  Please read license.txt for the full details. A copy of the GPL
-  may be found at http://www.gnu.org/copyleft/lgpl.html
-
-  You should have received a copy of the GNU General Public License
-  along with this program; if not, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- */
-package digilib.io;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.ListIterator;
-
-import digilib.image.DocuInfo;
-import digilib.image.ImageSize;
-
-/**
- * @author casties
- */
-public class DocuFileset {
-
-	// list of files (DocuFile)
-	private ArrayList list = null;
-	// metadata
-	private HashMap fileMeta = null;
-	// metadata has been checked
-	private boolean metaChecked = false;
-	// resolution (DPI)
-	private double resX = 0;
-	private double resY = 0;
-	// parent directory
-	private DocuDirectory parent = null;
-
-	/*
-	 * constructors
-	 */
-
-	public DocuFileset(int initialCapacity) {
-		list = new ArrayList(initialCapacity);
-	}
-
-	/*
-	 * other stuff
-	 */
-
-	/** Adds a DocuFile to this Fileset.
-	 * 
-	 * The files should be added in the order of higher to lower resolutions. 
-	 * The first file is considered the hires "original". 
-	 * 
-	 * @param f file to add
-	 * @return true (always)
-	 */
-	public boolean add(DocuFile f) {
-		f.setParent(this);
-		return list.add(f);
-	}
-
-	/** The number of image files in this Fileset.
-	 * 
-	 * @return number of image files
-	 */
-	public int size() {
-		return (list != null) ? list.size() : 0;
-	}
-
-	/** Get the DocuFile at the index.
-	 * 
-	 * @param index
-	 * @return
-	 */
-	public DocuFile get(int index) {
-		return (DocuFile) list.get(index);
-	}
-
-	/** Get the next smaller DocuFile than the given size.
-	 * 
-	 * Returns the DocuFile from the set that has a width and height 
-	 * smaller or equal the given size. 
-	 * Returns null if there isn't any smaller image.
-	 * Needs DocuInfo instance to checkFile().
-	 * 
-	 * @param size
-	 * @param info
-	 * @return
-	 */
-	public DocuFile getNextSmaller(ImageSize size, DocuInfo info) {
-		for (Iterator i = getHiresIterator(); i.hasNext();) {
-			DocuFile f = (DocuFile) i.next();
-			try {
-				if (!f.isChecked()) {
-					info.checkFile(f);
-				}
-				if (f.getSize().isTotallySmallerThan(size)) {
-					return f;
-				}
-			} catch (IOException e) {
-				// TODO Auto-generated catch block
-				e.printStackTrace();
-			}
-		}
-		return null;
-	}
-
-	/** Get the next bigger DocuFile than the given size.
-	 * 
-	 * Returns the DocuFile from the set that has a width or height 
-	 * bigger or equal the given size. 
-	 * Returns null if there isn't any bigger image.
-	 * Needs DocuInfo instance to checkFile().
-	 * 
-	 * @param size
-	 * @param info
-	 * @return
-	 */
-	public DocuFile getNextBigger(ImageSize size, DocuInfo info) {
-		for (ListIterator i = getLoresIterator(); i.hasPrevious();) {
-			DocuFile f = (DocuFile) i.previous();
-			try {
-				if (!f.isChecked()) {
-					info.checkFile(f);
-				}
-				if (f.getSize().isBiggerThan(size)) {
-					return f;
-				}
-			} catch (IOException e) {
-				// TODO Auto-generated catch block
-				e.printStackTrace();
-			}
-		}
-		return null;
-	}
-
-	/** Get an Iterator for this Fileset starting at the highest resolution 
-	 * images.
-	 * 
-	 * @return
-	 */
-	public ListIterator getHiresIterator() {
-		return list.listIterator();
-	}
-
-	/** Get an Iterator for this Fileset starting at the lowest resolution 
-	 * images.
-	 * 
-	 * The Iterator starts at the last element, so you have to use it backwards 
-	 * with hasPrevious() and previous().
-	 * 
-	 * @return
-	 */
-	public ListIterator getLoresIterator() {
-		return list.listIterator(list.size());
-	}
-
-	/** Reads meta-data for this Fileset if there is any.
-	 * 
-	 */
-	public void readMeta() {
-		if ((fileMeta != null) || list.isEmpty()) {
-			// there is already metadata or there's no file 
-			return;
-		}
-		// metadata is in the file {filename}.meta
-		String fn = ((DocuFile) list.get(0)).getFile().getAbsolutePath();
-		File mf = new File(fn + ".meta");
-		if (mf.canRead()) {
-			XMLMetaLoader ml = new XMLMetaLoader();
-			try {
-				// read meta file
-				HashMap meta = ml.loadURL(mf.getAbsolutePath());
-				if (meta == null) {
-					return;
-				}
-				fileMeta = (HashMap) meta.get(getName());
-			} catch (Exception e) {
-				// TODO Auto-generated catch block
-				e.printStackTrace();
-			}
-		}
-	}
-
-	/** Checks metadata and sets resolution in resX and resY.
-	 * 
-	 */
-	public void checkMeta() {
-		if (metaChecked) {
-			return;
-		}
-		if (fileMeta == null) {
-			// try to read metadata file
-			readMeta();
-			if (fileMeta == null) {
-				// try directory metadata
-				if (parent.getDirMeta() != null) {
-					fileMeta = parent.getDirMeta();
-				} else {
-					// no metadata available
-					metaChecked = true;
-					return;
-				}
-			}
-		}
-		metaChecked = true;
-		String s;
-		double dpi = 0;
-		double dpix = 0;
-		double dpiy = 0;
-		double sizex = 0;
-		double sizey = 0;
-		double pixx = 0;
-		double pixy = 0;
-		// DPI is valid for X and Y
-		if (fileMeta.containsKey("original-dpi")) {
-			try {
-				dpi = Double.parseDouble((String) fileMeta.get("original-dpi"));
-			} catch (NumberFormatException e) {
-			}
-			if (dpi != 0) {
-				resX = dpi;
-				resY = dpi;
-				return;
-			}
-		}
-		// DPI-X and DPI-Y
-		if (fileMeta.containsKey("original-dpi-x")
-			&& fileMeta.containsKey("original-dpi-y")) {
-			try {
-				dpix =
-					Double.parseDouble((String) fileMeta.get("original-dpi-x"));
-				dpiy =
-					Double.parseDouble((String) fileMeta.get("original-dpi-y"));
-			} catch (NumberFormatException e) {
-			}
-			if ((dpix != 0) && (dpiy != 0)) {
-				resX = dpix;
-				resY = dpiy;
-				return;
-			}
-		}
-		// SIZE-X and SIZE-Y and PIXEL-X and PIXEL-Y
-		if (fileMeta.containsKey("original-size-x")
-			&& fileMeta.containsKey("original-size-y")
-			&& fileMeta.containsKey("original-pixel-x")
-			&& fileMeta.containsKey("original-pixel-y")) {
-			try {
-				sizex =
-					Double.parseDouble(
-						(String) fileMeta.get("original-size-x"));
-				sizey =
-					Double.parseDouble(
-						(String) fileMeta.get("original-size-y"));
-				pixx =
-					Double.parseDouble(
-						(String) fileMeta.get("original-pixel-x"));
-				pixy =
-					Double.parseDouble(
-						(String) fileMeta.get("original-pixel-y"));
-			} catch (NumberFormatException e) {
-			}
-			if ((sizex != 0) && (sizey != 0) && (pixx != 0) && (pixy != 0)) {
-				resX = pixx / (sizex * 100 / 2.54);
-				resY = pixy / (sizey * 100 / 2.54);
-				return;
-			}
-		}
-	}
-
-	/** The name of the (hires) image file.
-	 * 
-	 * @return
-	 */
-	public String getName() {
-		if (!list.isEmpty()) {
-			return ((DocuFile) list.get(0)).getName();
-		}
-		return null;
-	}
-
-	/** Returns the parent DocuDirectory.
-	 * 
-	 * @return DocuDirectory
-	 */
-	public DocuDirectory getParent() {
-		return parent;
-	}
-
-	/**
-	 * Sets the parent.
-	 * @param parent The parent to set
-	 */
-	public void setParent(DocuDirectory parent) {
-		this.parent = parent;
-	}
-
-	/** Returns the meta-data for this fileset.
-	 * 
-	 * @return HashMap
-	 */
-	public HashMap getFileMeta() {
-		return fileMeta;
-	}
-
-	/**
-	 * Sets the fileMeta.
-	 * @param fileMeta The fileMeta to set
-	 */
-	public void setFileMeta(HashMap fileMeta) {
-		this.fileMeta = fileMeta;
-	}
-
-	/**
-	 * @return
-	 */
-	public boolean isMetaChecked() {
-		return metaChecked;
-	}
-
-	/**
-	 * @return
-	 */
-	public double getResX() {
-		return resX;
-	}
-
-	/**
-	 * @return
-	 */
-	public double getResY() {
-		return resY;
-	}
-
-}
--- a/servlet/src/digilib/io/FileOps.java	Tue Sep 16 18:26:31 2003 +0200
+++ b/servlet/src/digilib/io/FileOps.java	Tue Sep 16 18:32:00 2003 +0200
@@ -20,14 +20,18 @@
 
 package digilib.io;
 
-import java.io.*;
-import java.util.*;
+import java.io.File;
+import java.io.FileFilter;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.StringTokenizer;
 
-import digilib.*;
+import digilib.Utils;
 
 public class FileOps {
 
 	private Utils util = null;
+	
 	public static String[] fileTypes =
 		{
 			"jpg",
@@ -43,11 +47,28 @@
 			"tif",
 			"image/tiff",
 			"tiff",
-			"image/tiff" };
+			"image/tiff",
+			"txt",
+			"text/plain",
+			"html",
+			"text/html",
+			"htm",
+			"text/html",
+			"xml",
+			"text/xml" };
 
-	public static String[] fileExtensions =
+	public static String[] imageExtensions =
 		{ "jpg", "jpeg", "jp2", "png", "gif", "tif", "tiff" };
 
+	public static String[] textExtensions =
+		{ "txt", "html", "htm", "xml"};
+		
+	public static final int CLASS_NONE = -1;
+	public static final int CLASS_IMAGE = 0;
+	public static final int CLASS_TEXT = 1;
+	public static final int NUM_CLASSES = 2;
+	
+
 	public FileOps() {
 		util = new Utils();
 	}
@@ -73,18 +94,43 @@
 		return null;
 	}
 
-	public static Iterator getImageExtensionIterator() {
-		return Arrays.asList(fileExtensions).iterator();
+	/**
+	 * get the file class for the filename (by extension)
+	 * @param fn
+	 * @return
+	 */
+	public static int classForFilename(String fn) {
+		int n = imageExtensions.length;
+		for (int i = 0; i < n; i ++) {
+			if (fn.toLowerCase().endsWith(imageExtensions[i])) {
+				return CLASS_IMAGE;
+			}
+		}
+		n = textExtensions.length;
+		for (int i = 0; i < n; i ++) {
+			if (fn.toLowerCase().endsWith(textExtensions[i])) {
+				return CLASS_TEXT;
+			}
+		}
+		return CLASS_NONE;
+		
 	}
 
+	public static Iterator getImageExtensionIterator() {
+		return Arrays.asList(imageExtensions).iterator();
+	}
+
+	public static Iterator getTextExtensionIterator() {
+		return Arrays.asList(textExtensions).iterator();
+	}
+	
 	/**
 	 * convert a string with a list of pathnames into an array of strings
 	 * using the system's path separator string
 	 */
 	public static String[] pathToArray(String paths) {
 		// split list into directories
-		StringTokenizer dirs =
-			new StringTokenizer(paths, File.pathSeparator);
+		StringTokenizer dirs = new StringTokenizer(paths, File.pathSeparator);
 		int n = dirs.countTokens();
 		if (n < 1) {
 			return null;
@@ -104,114 +150,46 @@
 	}
 
 	/**
-	 *  get a filehandle for a file or directory name
-	 *    returns File number n if fn is directory (starts with 1)
-	 */
-	public File getFile(String fn, int n) throws FileOpException {
-		util.dprintln(4, "getFile (" + fn + ", " + n + ")");
-
-		File f = new File(fn);
-		// if fn is a file name then return file
-		if (f.isFile()) {
-			return f;
-		}
-		// if fn is a directory name then open directory
-		if (f.isDirectory()) {
-			File[] fl = f.listFiles(new ImageFileFilter());
-			Arrays.sort(fl);
-			if ((n > 0) && (n <= fl.length)) {
-				return fl[n - 1];
-			}
-		}
-		throw new FileOpException("Unable to find file: " + fn);
-	}
-
-	/**
-	 *  get the number of files in a directory
-	 *    (almost the same as getFile)
-	 *  returns 0 in case of problems
-	 */
-	public int getNumFiles(String fn) throws FileOpException {
-		util.dprintln(4, "getNumFiles (" + fn + ")");
-
-		File f = new File(fn);
-		// if fn is a file name then return 1
-		if (f.isFile()) {
-			return 1;
-		}
-		// if fn is a directory name then return the number of files
-		if (f.isDirectory()) {
-			return f.listFiles(new ImageFileFilter()).length;
-		}
-		// then fn must be something strange...
-		return 0;
-	}
-
-	/**
-	 *  get a filehandle for a file or directory name out of a list
-	 *    dirs is a list of base directories, fn is the appended file/dirname
-	 *    searches dirs until fn exists (backwards if fwd is false)
-	 *    returns File number n if fn is directory (starts with 1)
-	 */
-	public File getFileVariant(String[] dirs, String fn, int n, boolean fwd)
-		throws FileOpException {
-		util.dprintln(
-			4,
-			"getVariantFile (" + dirs + ", " + fn + ", " + n + ")");
-
-		File f = null;
-		int nvar = dirs.length;
-
-		for (int i = 0; i < nvar; i++) {
-			try {
-				f = getFile(dirs[(fwd) ? i : (nvar - i - 1)] + fn, n);
-			} catch (FileOpException e) {
-				f = null;
-			}
-			if (f != null) {
-				return f;
-			}
-		}
-		throw new FileOpException("Unable to find file: " + fn);
-	}
-
-	/**
-	 *  get the number of files in a directory
-	 *    (almost the same as getFileVariant)
-	 *  returns 0 in case of problems
-	 */
-	public int getNumFilesVariant(String[] dirs, String fn, boolean fwd)
-		throws FileOpException {
-		util.dprintln(4, "getNumFilesVariant (" + dirs + ", " + fn + ")");
-
-		int nf = 0;
-		int nvar = dirs.length;
-
-		for (int i = 0; i < nvar; i++) {
-			try {
-				nf = getNumFiles(dirs[(fwd) ? i : (nvar - i - 1)] + fn);
-			} catch (FileOpException e) {
-				nf = 0;
-			}
-			if (nf > 0) {
-				return nf;
-			}
-		}
-		return 0;
-	}
-
-	/**
 	 *  FileFilter for image types (helper class for getFile)
 	 */
 	static class ImageFileFilter implements FileFilter {
 
 		public boolean accept(File f) {
 			if (f.isFile()) {
-				return (mimeForFile(f) != null);
+				return ((mimeForFile(f) != null)&&(mimeForFile(f).startsWith("image")));
 			} else {
 				return false;
 			}
 		}
 	}
 
+	/**
+	 *  FileFilter for text types (helper class for getFile)
+	 */
+	static class TextFileFilter implements FileFilter {
+
+		public boolean accept(File f) {
+			if (f.isFile()) {
+				return ((mimeForFile(f) != null)&&(mimeForFile(f).startsWith("text")));
+			} else {
+				return false;
+			}
+		}
+	}
+
+	/** Factory for FileFilters (image or text).
+	 * 
+	 * @param fileClass
+	 * @return
+	 */ 
+	public static FileFilter filterForClass(int fileClass) {
+		if (fileClass == CLASS_IMAGE) {
+			return new ImageFileFilter();
+		}
+		if (fileClass == CLASS_TEXT) {
+			return new TextFileFilter();
+		}
+		return null;
+	}
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/ImageFile.java	Tue Sep 16 18:32:00 2003 +0200
@@ -0,0 +1,128 @@
+/* ImageFile.java -- digilib image file class.
+
+  Digital Image Library servlet components
+
+  Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
+
+  This program is free software; you can redistribute  it and/or modify it
+  under  the terms of  the GNU General  Public License as published by the
+  Free Software Foundation;  either version 2 of the  License, or (at your
+  option) any later version.
+   
+  Please read license.txt for the full details. A copy of the GPL
+  may be found at http://www.gnu.org/copyleft/lgpl.html
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ * Created on 25.02.2003
+ */
+ 
+package digilib.io;
+
+import java.io.File;
+
+import digilib.image.ImageSize;
+
+/**
+ * @author casties
+ */
+public class ImageFile {
+	
+	// file name
+	private String filename = null;
+	// parent ImageFileset
+	private ImageFileset parent = null;
+	// parent directory
+	private Directory dir = null;
+	// mime file type
+	private String mimetype = null;
+	// image size in pixels
+	private ImageSize pixelSize = null;
+
+	public ImageFile(String fn, ImageFileset parent, Directory dir) {
+		this.filename = fn;
+		this.parent = parent;
+		this.dir = dir;
+	}
+	
+	public ImageFile(String fn) {
+		File f = new File(fn);
+		this.dir = new Directory(f.getParentFile());
+		this.filename = f.getName();
+	}
+	
+	/** Returns the file name (without path).
+	 * 
+	 * @return
+	 */
+	public String getName() {
+		return filename;
+	}
+
+
+	/**
+	 * @return File
+	 */
+	public File getFile() {
+		if (dir == null) {
+			return null;
+		}
+		File f = new File(dir.getDir(), filename);
+		return f;
+	}
+
+	/**
+	 * @return ImageSize
+	 */
+	public ImageSize getSize() {
+		return pixelSize;
+	}
+
+	/**
+	 * @return String
+	 */
+	public String getMimetype() {
+		return mimetype;
+	}
+
+	/**
+	 * Sets the imageSize.
+	 * @param imageSize The imageSize to set
+	 */
+	public void setSize(ImageSize imageSize) {
+		this.pixelSize = imageSize;
+	}
+
+	/**
+	 * Sets the mimetype.
+	 * @param mimetype The mimetype to set
+	 */
+	public void setMimetype(String mimetype) {
+		this.mimetype = mimetype;
+	}
+
+	/**
+	 * @return ImageFileset
+	 */
+	public ImageFileset getParent() {
+		return parent;
+	}
+
+	/**
+	 * Sets the parent.
+	 * @param parent The parent to set
+	 */
+	public void setParent(ImageFileset parent) {
+		this.parent = parent;
+	}
+
+	/**
+	 * @return boolean
+	 */
+	public boolean isChecked() {
+		return (pixelSize != null);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/ImageFileset.java	Tue Sep 16 18:32:00 2003 +0200
@@ -0,0 +1,333 @@
+/* ImageFileset -- digilib image file info class.
+
+  Digital Image Library servlet components
+
+  Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
+
+  This program is free software; you can redistribute  it and/or modify it
+  under  the terms of  the GNU General  Public License as published by the
+  Free Software Foundation;  either version 2 of the  License, or (at your
+  option) any later version.
+   
+  Please read license.txt for the full details. A copy of the GPL
+  may be found at http://www.gnu.org/copyleft/lgpl.html
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+package digilib.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.ListIterator;
+
+import digilib.image.DocuInfo;
+import digilib.image.ImageSize;
+
+/**
+ * @author casties
+ */
+public class ImageFileset extends DocuDirent {
+
+	// this is an image file
+	protected static int fileClass = FileOps.CLASS_IMAGE;
+
+	// list of files (ImageFile)
+	private ArrayList list = null;
+	// resolution (DPI)
+	private double resX = 0;
+	private double resY = 0;
+
+	/** Creator for empty fileset with size for file list.
+	 * 
+	 * @param initialCapacity
+	 */
+	public ImageFileset(int initialCapacity) {
+		list = new ArrayList(initialCapacity);
+	}
+
+	/** Creator with a file and base directories.
+	 * 
+	 * Reads the file and fills the 
+	 * fileset with corresponding files from the other base directories.
+	 * First entry in dirs is the parent of this fileset. 
+	 * 
+	 * @see fill
+	 * 
+	 * @param dirs array of base directories
+	 * @param file first file to read
+	 * @param scalext extension for scaled images
+	 */
+	public ImageFileset(Directory[] dirs, File file, String scalext) {
+		int nb = dirs.length;
+		list = new ArrayList(nb);
+		parent = dirs[0];
+		fill(dirs, file, scalext);
+	}
+
+	/** Adds a ImageFile to this Fileset.
+	 * 
+	 * The files should be added in the order of higher to lower resolutions. 
+	 * The first file is considered the hires "original". 
+	 * 
+	 * @param f file to add
+	 * @return true (always)
+	 */
+	public boolean add(ImageFile f) {
+		f.setParent(this);
+		return list.add(f);
+	}
+
+	/** The number of image files in this Fileset.
+	 * 
+	 * @return number of image files
+	 */
+	public int size() {
+		return (list != null) ? list.size() : 0;
+	}
+
+	/** Gets the default File.
+	 * 
+	 */
+	public File getFile() {
+		return (list != null) ? ((ImageFile) list.get(0)).getFile() : null;
+	}
+
+	/** Get the ImageFile at the index.
+	 * 
+	 * @param index
+	 * @return
+	 */
+	public ImageFile get(int index) {
+		return (ImageFile) list.get(index);
+	}
+
+	/** Get the next smaller ImageFile than the given size.
+	 * 
+	 * Returns the ImageFile from the set that has a width and height 
+	 * smaller or equal the given size. 
+	 * Returns null if there isn't any smaller image.
+	 * Needs DocuInfo instance to checkFile().
+	 * 
+	 * @param size
+	 * @param info
+	 * @return
+	 */
+	public ImageFile getNextSmaller(ImageSize size, DocuInfo info) {
+		for (Iterator i = getHiresIterator(); i.hasNext();) {
+			ImageFile f = (ImageFile) i.next();
+			try {
+				if (!f.isChecked()) {
+					info.checkFile(f);
+				}
+				if (f.getSize().isTotallySmallerThan(size)) {
+					return f;
+				}
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		return null;
+	}
+
+	/** Get the next bigger ImageFile than the given size.
+	 * 
+	 * Returns the ImageFile from the set that has a width or height 
+	 * bigger or equal the given size. 
+	 * Returns null if there isn't any bigger image.
+	 * Needs DocuInfo instance to checkFile().
+	 * 
+	 * @param size
+	 * @param info
+	 * @return
+	 */
+	public ImageFile getNextBigger(ImageSize size, DocuInfo info) {
+		for (ListIterator i = getLoresIterator(); i.hasPrevious();) {
+			ImageFile f = (ImageFile) i.previous();
+			try {
+				if (!f.isChecked()) {
+					info.checkFile(f);
+				}
+				if (f.getSize().isBiggerThan(size)) {
+					return f;
+				}
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		return null;
+	}
+
+	/** Get an Iterator for this Fileset starting at the highest resolution 
+	 * images.
+	 * 
+	 * @return
+	 */
+	public ListIterator getHiresIterator() {
+		return list.listIterator();
+	}
+
+	/** Get an Iterator for this Fileset starting at the lowest resolution 
+	 * images.
+	 * 
+	 * The Iterator starts at the last element, so you have to use it backwards 
+	 * with hasPrevious() and previous().
+	 * 
+	 * @return
+	 */
+	public ListIterator getLoresIterator() {
+		return list.listIterator(list.size());
+	}
+
+	/** Fill the ImageFileset with files from different base directories.
+	 * 
+	 * @param dirs list of base directories
+	 * @param fl file (from first base dir)
+	 * @param scalext first extension to try in other base dirs
+	 */
+	void fill(Directory[] dirs, File fl, String scalext) {
+		int nb = dirs.length;
+		String fn = fl.getName();
+		String fnx = fn.substring(0, fn.lastIndexOf('.') + 1);
+		// add the first ImageFile to the ImageFileset 
+		add(new ImageFile(fn, this, parent));
+		// iterate the remaining base directories
+		for (int j = 1; j < nb; j++) {
+			if (dirs[j] == null) {
+				continue;
+			}
+			File f;
+			if (scalext != null) {
+				// use the last extension
+				f = new File(dirs[j].getDir(), fnx + scalext);
+			} else {
+				// try the same filename as the original
+				f = new File(dirs[j].getDir(), fn);
+			}
+			// if the file exists, add to the ImageFileset
+			if (f.canRead()) {
+				add(new ImageFile(f.getName(), this, dirs[j]));
+			} else {
+				// try other file extensions
+				Iterator exts = FileOps.getImageExtensionIterator();
+				while (exts.hasNext()) {
+					String s = (String) exts.next();
+					f = new File(dirs[j].getDir(), fnx + s);
+					// if the file exists, add to the ImageFileset
+					if (f.canRead()) {
+						add(new ImageFile(f.getName(), this, dirs[j]));
+						scalext = s;
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	/** Checks metadata and sets resolution in resX and resY.
+	 * 
+	 */
+	public void checkMeta() {
+		if (metaChecked) {
+			return;
+		}
+		if (fileMeta == null) {
+			// try to read metadata file
+			readMeta();
+			if (fileMeta == null) {
+				// try directory metadata
+				if (((DocuDirectory) parent).getDirMeta() != null) {
+					fileMeta = ((DocuDirectory) parent).getDirMeta();
+				} else {
+					// no metadata available
+					metaChecked = true;
+					return;
+				}
+			}
+		}
+		metaChecked = true;
+		String s;
+		double dpi = 0;
+		double dpix = 0;
+		double dpiy = 0;
+		double sizex = 0;
+		double sizey = 0;
+		double pixx = 0;
+		double pixy = 0;
+		// DPI is valid for X and Y
+		if (fileMeta.containsKey("original-dpi")) {
+			try {
+				dpi = Double.parseDouble((String) fileMeta.get("original-dpi"));
+			} catch (NumberFormatException e) {
+			}
+			if (dpi != 0) {
+				resX = dpi;
+				resY = dpi;
+				return;
+			}
+		}
+		// DPI-X and DPI-Y
+		if (fileMeta.containsKey("original-dpi-x")
+			&& fileMeta.containsKey("original-dpi-y")) {
+			try {
+				dpix =
+					Double.parseDouble((String) fileMeta.get("original-dpi-x"));
+				dpiy =
+					Double.parseDouble((String) fileMeta.get("original-dpi-y"));
+			} catch (NumberFormatException e) {
+			}
+			if ((dpix != 0) && (dpiy != 0)) {
+				resX = dpix;
+				resY = dpiy;
+				return;
+			}
+		}
+		// SIZE-X and SIZE-Y and PIXEL-X and PIXEL-Y
+		if (fileMeta.containsKey("original-size-x")
+			&& fileMeta.containsKey("original-size-y")
+			&& fileMeta.containsKey("original-pixel-x")
+			&& fileMeta.containsKey("original-pixel-y")) {
+			try {
+				sizex =
+					Double.parseDouble(
+						(String) fileMeta.get("original-size-x"));
+				sizey =
+					Double.parseDouble(
+						(String) fileMeta.get("original-size-y"));
+				pixx =
+					Double.parseDouble(
+						(String) fileMeta.get("original-pixel-x"));
+				pixy =
+					Double.parseDouble(
+						(String) fileMeta.get("original-pixel-y"));
+			} catch (NumberFormatException e) {
+			}
+			if ((sizex != 0) && (sizey != 0) && (pixx != 0) && (pixy != 0)) {
+				resX = pixx / (sizex * 100 / 2.54);
+				resY = pixy / (sizey * 100 / 2.54);
+				return;
+			}
+		}
+	}
+
+	/**
+	 * @return
+	 */
+	public double getResX() {
+		return resX;
+	}
+
+	/**
+	 * @return
+	 */
+	public double getResY() {
+		return resY;
+	}
+
+}